/* * Copyright 2010, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #include #include #include #include #include #include #include #include static int family_from_interface_address(const BNetworkInterfaceAddress& address) { if (address.Address().Family() != AF_UNSPEC) return address.Address().Family(); if (address.Mask().Family() != AF_UNSPEC) return address.Mask().Family(); if (address.Destination().Family() != AF_UNSPEC) return address.Destination().Family(); return AF_INET; } static status_t do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address, bool readBack = false) { int family = AF_INET; if (!readBack) family = family_from_interface_address(address); FileDescriptorCloser socket(::socket(family, SOCK_DGRAM, 0)); if (!socket.IsSet()) return errno; ifaliasreq request; strlcpy(request.ifra_name, name, IF_NAMESIZE); request.ifra_index = address.Index(); request.ifra_flags = address.Flags(); memcpy(&request.ifra_addr, &address.Address().SockAddr(), address.Address().Length()); memcpy(&request.ifra_mask, &address.Mask().SockAddr(), address.Mask().Length()); memcpy(&request.ifra_broadaddr, &address.Broadcast().SockAddr(), address.Broadcast().Length()); if (ioctl(socket.Get(), option, &request, sizeof(struct ifaliasreq)) < 0) return errno; if (readBack) { address.SetFlags(request.ifra_flags); address.Address().SetTo(request.ifra_addr); address.Mask().SetTo(request.ifra_mask); address.Broadcast().SetTo(request.ifra_broadaddr); } return B_OK; } static status_t do_ifaliasreq(const char* name, int32 option, const BNetworkInterfaceAddress& address) { return do_ifaliasreq(name, option, const_cast(address)); } template status_t do_request(int family, T& request, const char* name, int option) { FileDescriptorCloser socket(::socket(family, SOCK_DGRAM, 0)); if (!socket.IsSet()) return errno; strlcpy(((struct ifreq&)request).ifr_name, name, IF_NAMESIZE); if (ioctl(socket.Get(), option, &request, sizeof(T)) < 0) return errno; return B_OK; } // #pragma mark - BNetworkInterfaceAddress::BNetworkInterfaceAddress() : fIndex(-1), fFlags(0) { } BNetworkInterfaceAddress::~BNetworkInterfaceAddress() { } status_t BNetworkInterfaceAddress::SetTo(const BNetworkInterface& interface, int32 index) { fIndex = index; return do_ifaliasreq(interface.Name(), B_SOCKET_GET_ALIAS, *this, true); } void BNetworkInterfaceAddress::SetAddress(const BNetworkAddress& address) { fAddress = address; } void BNetworkInterfaceAddress::SetMask(const BNetworkAddress& mask) { fMask = mask; } void BNetworkInterfaceAddress::SetBroadcast(const BNetworkAddress& broadcast) { fBroadcast = broadcast; } void BNetworkInterfaceAddress::SetDestination(const BNetworkAddress& destination) { fBroadcast = destination; } void BNetworkInterfaceAddress::SetFlags(uint32 flags) { fFlags = flags; } // #pragma mark - BNetworkInterface::BNetworkInterface() { Unset(); } BNetworkInterface::BNetworkInterface(const char* name) { SetTo(name); } BNetworkInterface::BNetworkInterface(uint32 index) { SetTo(index); } BNetworkInterface::~BNetworkInterface() { } void BNetworkInterface::Unset() { fName[0] = '\0'; } void BNetworkInterface::SetTo(const char* name) { strlcpy(fName, name, IF_NAMESIZE); } status_t BNetworkInterface::SetTo(uint32 index) { ifreq request; request.ifr_index = index; status_t status = do_request(AF_INET, request, "", SIOCGIFNAME); if (status != B_OK) return status; strlcpy(fName, request.ifr_name, IF_NAMESIZE); return B_OK; } bool BNetworkInterface::Exists() const { ifreq request; return do_request(AF_INET, request, Name(), SIOCGIFINDEX) == B_OK; } const char* BNetworkInterface::Name() const { return fName; } uint32 BNetworkInterface::Index() const { ifreq request; if (do_request(AF_INET, request, Name(), SIOCGIFINDEX) != B_OK) return 0; return request.ifr_index; } uint32 BNetworkInterface::Flags() const { ifreq request; if (do_request(AF_INET, request, Name(), SIOCGIFFLAGS) != B_OK) return 0; return request.ifr_flags; } uint32 BNetworkInterface::MTU() const { ifreq request; if (do_request(AF_INET, request, Name(), SIOCGIFMTU) != B_OK) return 0; return request.ifr_mtu; } int32 BNetworkInterface::Media() const { ifreq request; if (do_request(AF_INET, request, Name(), SIOCGIFMEDIA) != B_OK) return -1; return request.ifr_media; } uint32 BNetworkInterface::Metric() const { ifreq request; if (do_request(AF_INET, request, Name(), SIOCGIFMETRIC) != B_OK) return 0; return request.ifr_metric; } uint32 BNetworkInterface::Type() const { ifreq request; if (do_request(AF_INET, request, Name(), SIOCGIFTYPE) != B_OK) return 0; return request.ifr_type; } status_t BNetworkInterface::GetStats(ifreq_stats& stats) { ifreq request; status_t status = do_request(AF_INET, request, Name(), SIOCGIFSTATS); if (status != B_OK) return status; memcpy(&stats, &request.ifr_stats, sizeof(ifreq_stats)); return B_OK; } bool BNetworkInterface::HasLink() const { return (Flags() & IFF_LINK) != 0; } status_t BNetworkInterface::SetFlags(uint32 flags) { ifreq request; request.ifr_flags = flags; return do_request(AF_INET, request, Name(), SIOCSIFFLAGS); } status_t BNetworkInterface::SetMTU(uint32 mtu) { ifreq request; request.ifr_mtu = mtu; return do_request(AF_INET, request, Name(), SIOCSIFMTU); } status_t BNetworkInterface::SetMedia(int32 media) { ifreq request; request.ifr_media = media; return do_request(AF_INET, request, Name(), SIOCSIFMEDIA); } status_t BNetworkInterface::SetMetric(uint32 metric) { ifreq request; request.ifr_metric = metric; return do_request(AF_INET, request, Name(), SIOCSIFMETRIC); } int32 BNetworkInterface::CountAddresses() const { ifreq request; if (do_request(AF_INET, request, Name(), B_SOCKET_COUNT_ALIASES) != B_OK) return 0; return request.ifr_count; } status_t BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address) { return address.SetTo(*this, index); } int32 BNetworkInterface::FindAddress(const BNetworkAddress& address) { FileDescriptorCloser socket(::socket(address.Family(), SOCK_DGRAM, 0)); if (!socket.IsSet()) return -1; ifaliasreq request; memset(&request, 0, sizeof(ifaliasreq)); strlcpy(request.ifra_name, Name(), IF_NAMESIZE); request.ifra_index = -1; memcpy(&request.ifra_addr, &address.SockAddr(), address.Length()); if (ioctl(socket.Get(), B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq)) < 0) { return -1; } return request.ifra_index; } int32 BNetworkInterface::FindFirstAddress(int family) { FileDescriptorCloser socket(::socket(family, SOCK_DGRAM, 0)); if (!socket.IsSet()) return -1; ifaliasreq request; memset(&request, 0, sizeof(ifaliasreq)); strlcpy(request.ifra_name, Name(), IF_NAMESIZE); request.ifra_index = -1; request.ifra_addr.ss_family = AF_UNSPEC; if (ioctl(socket.Get(), B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq)) < 0) { return -1; } return request.ifra_index; } status_t BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address) { return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); } status_t BNetworkInterface::AddAddress(const BNetworkAddress& local) { BNetworkInterfaceAddress address; address.SetAddress(local); return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); } status_t BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address) { return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address); } status_t BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address) { ifreq request; memcpy(&request.ifr_addr, &address.Address().SockAddr(), address.Address().Length()); return do_request(family_from_interface_address(address), request, Name(), B_SOCKET_REMOVE_ALIAS); } status_t BNetworkInterface::RemoveAddress(const BNetworkAddress& address) { ifreq request; memcpy(&request.ifr_addr, &address.SockAddr(), address.Length()); return do_request(address.Family(), request, Name(), B_SOCKET_REMOVE_ALIAS); } status_t BNetworkInterface::RemoveAddressAt(int32 index) { BNetworkInterfaceAddress address; status_t status = GetAddressAt(index, address); if (status != B_OK) return status; return RemoveAddress(address); } status_t BNetworkInterface::GetHardwareAddress(BNetworkAddress& address) { FileDescriptorCloser socket(::socket(AF_LINK, SOCK_DGRAM, 0)); if (!socket.IsSet()) return errno; ifreq request; strlcpy(request.ifr_name, Name(), IF_NAMESIZE); if (ioctl(socket.Get(), SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0) return errno; address.SetTo(request.ifr_addr); return B_OK; } status_t BNetworkInterface::AddRoute(const BNetworkRoute& route) { int family = route.AddressFamily(); if (family == AF_UNSPEC) return B_BAD_VALUE; ifreq request; request.ifr_route = route.RouteEntry(); return do_request(family, request, Name(), SIOCADDRT); } status_t BNetworkInterface::AddDefaultRoute(const BNetworkAddress& gateway) { BNetworkRoute route; status_t result = route.SetGateway(gateway); if (result != B_OK) return result; route.SetFlags(RTF_STATIC | RTF_DEFAULT | RTF_GATEWAY); return AddRoute(route); } status_t BNetworkInterface::RemoveRoute(const BNetworkRoute& route) { int family = route.AddressFamily(); if (family == AF_UNSPEC) return B_BAD_VALUE; return RemoveRoute(family, route); } status_t BNetworkInterface::RemoveRoute(int family, const BNetworkRoute& route) { ifreq request; request.ifr_route = route.RouteEntry(); return do_request(family, request, Name(), SIOCDELRT); } status_t BNetworkInterface::RemoveDefaultRoute(int family) { BNetworkRoute route; route.SetFlags(RTF_STATIC | RTF_DEFAULT); return RemoveRoute(family, route); } status_t BNetworkInterface::GetRoutes(int family, BObjectList& routes) const { return BNetworkRoute::GetRoutes(family, Name(), routes); } status_t BNetworkInterface::GetDefaultRoute(int family, BNetworkRoute& route) const { return BNetworkRoute::GetDefaultRoute(family, Name(), route); } status_t BNetworkInterface::GetDefaultGateway(int family, BNetworkAddress& gateway) const { return BNetworkRoute::GetDefaultGateway(family, Name(), gateway); } status_t BNetworkInterface::AutoConfigure(int family) { BMessage message(kMsgConfigureInterface); message.AddString("device", Name()); BMessage address; address.AddInt32("family", family); address.AddBool("auto_config", true); message.AddMessage("address", &address); BMessenger networkServer(kNetServerSignature); BMessage reply; status_t status = networkServer.SendMessage(&message, &reply); if (status == B_OK) reply.FindInt32("status", &status); return status; }