NetServer: Add IPv6 link local address to each nic on boot
* Remove old ioctl code, cleanup AutoLooper. * Move link local code into NetServer AutoLooper should only be used for things that count as "auto-configuration" such as DHCP, router advertisements, and DHCPv6 * Properly form IPv6 link local address from MAC address * I think some IPv6 routes are needed still for proper local link connectivity. * Duplicate Address Detection is still a TODO * Style cleanup
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
|
* Copyright 2006-2012, Haiku, Inc. All Rights Reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Axel Dörfler, [email protected]
|
* Axel Dörfler, [email protected]
|
||||||
|
* Alexander von Gluck, [email protected]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -33,7 +34,6 @@ AutoconfigLooper::AutoconfigLooper(BMessenger target, const char* device)
|
|||||||
fDevice(device),
|
fDevice(device),
|
||||||
fCurrentClient(NULL)
|
fCurrentClient(NULL)
|
||||||
{
|
{
|
||||||
memset(fCurrentMac, 0, sizeof(fCurrentMac));
|
|
||||||
BMessage ready(kMsgReadyToRun);
|
BMessage ready(kMsgReadyToRun);
|
||||||
PostMessage(&ready);
|
PostMessage(&ready);
|
||||||
}
|
}
|
||||||
@@ -60,12 +60,12 @@ void
|
|||||||
AutoconfigLooper::_ConfigureIPv4()
|
AutoconfigLooper::_ConfigureIPv4()
|
||||||
{
|
{
|
||||||
// start with DHCP
|
// start with DHCP
|
||||||
|
|
||||||
if (fCurrentClient == NULL) {
|
if (fCurrentClient == NULL) {
|
||||||
fCurrentClient = new DHCPClient(fTarget, fDevice.String());
|
fCurrentClient = new DHCPClient(fTarget, fDevice.String());
|
||||||
AddHandler(fCurrentClient);
|
AddHandler(fCurrentClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set IFF_CONFIGURING flag on interface
|
// set IFF_CONFIGURING flag on interface
|
||||||
|
|
||||||
BNetworkInterface interface(fDevice.String());
|
BNetworkInterface interface(fDevice.String());
|
||||||
@@ -120,157 +120,12 @@ AutoconfigLooper::_ConfigureIPv4()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef INET6
|
|
||||||
static in6_addr
|
|
||||||
BuildIPv6LinkLocalAddress(uint8 mac[6])
|
|
||||||
{
|
|
||||||
in6_addr result;
|
|
||||||
|
|
||||||
result.s6_addr[0] = 0xfe;
|
|
||||||
result.s6_addr[1] = 0x80;
|
|
||||||
result.s6_addr[2] = 0;
|
|
||||||
result.s6_addr[3] = 0;
|
|
||||||
result.s6_addr[4] = 0;
|
|
||||||
result.s6_addr[5] = 0;
|
|
||||||
result.s6_addr[6] = 0;
|
|
||||||
result.s6_addr[7] = 0;
|
|
||||||
|
|
||||||
result.s6_addr[8] = mac[0] ^ 0x02;
|
|
||||||
result.s6_addr[9] = mac[1];
|
|
||||||
result.s6_addr[10] = mac[2];
|
|
||||||
result.s6_addr[11] = 0xff;
|
|
||||||
result.s6_addr[12] = 0xfe;
|
|
||||||
result.s6_addr[13] = mac[3];
|
|
||||||
result.s6_addr[14] = mac[4];
|
|
||||||
result.s6_addr[15] = mac[5];
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
AutoconfigLooper::_ConfigureIPv6LinkLocal(bool add)
|
|
||||||
{
|
|
||||||
// do not touch the loopback device
|
|
||||||
if (!strncmp(fDevice.String(), "loop", 4))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ifreq request;
|
|
||||||
if (!prepare_request(request, fDevice.String()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
int socket = ::socket(AF_INET6, SOCK_DGRAM, 0);
|
|
||||||
if (socket < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// set IFF_CONFIGURING flag on interface
|
|
||||||
if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) == 0) {
|
|
||||||
request.ifr_flags |= IFF_CONFIGURING;
|
|
||||||
ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 mac[6];
|
|
||||||
memcpy(mac, fCurrentMac, 6);
|
|
||||||
if (add == true) {
|
|
||||||
if (get_mac_address(fDevice.String(), mac) != B_OK)
|
|
||||||
add = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (add == true) {
|
|
||||||
in6_addr inetAddress = BuildIPv6LinkLocalAddress(mac);
|
|
||||||
if (_AddIPv6LinkLocal(socket, inetAddress) != true)
|
|
||||||
add = false;
|
|
||||||
|
|
||||||
// save the MAC address for later usage
|
|
||||||
memcpy(fCurrentMac, mac, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (add == false) {
|
|
||||||
static const uint8 zeroMac[6] = {0};
|
|
||||||
if (memcmp(fCurrentMac, zeroMac, 6)) {
|
|
||||||
in6_addr inetAddress = BuildIPv6LinkLocalAddress(fCurrentMac);
|
|
||||||
_RemoveIPv6LinkLocal(socket, inetAddress);
|
|
||||||
// reset the stored MAC address
|
|
||||||
memcpy(fCurrentMac, zeroMac, 6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) == 0
|
|
||||||
&& (request.ifr_flags & IFF_CONFIGURING) == 0) {
|
|
||||||
// Someone else configured the interface in the mean time
|
|
||||||
close(socket);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
AutoconfigLooper::_AddIPv6LinkLocal(int socket, const in6_addr &address)
|
|
||||||
{
|
|
||||||
struct ifreq request;
|
|
||||||
if (!prepare_request(request, fDevice.String()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ifaliasreq aliasRequest;
|
|
||||||
memset(&aliasRequest, 0, sizeof(ifaliasreq));
|
|
||||||
strlcpy(aliasRequest.ifra_name, fDevice.String(), IF_NAMESIZE);
|
|
||||||
aliasRequest.ifra_addr.ss_len = sizeof(sockaddr_in6);
|
|
||||||
aliasRequest.ifra_addr.ss_family = AF_INET6;
|
|
||||||
|
|
||||||
if (ioctl(socket, SIOCAIFADDR, &aliasRequest, sizeof(ifaliasreq)) < 0) {
|
|
||||||
if (errno != B_NAME_IN_USE)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sockaddr_in6* socketAddress = (sockaddr_in6*)&request.ifr_addr;
|
|
||||||
socketAddress->sin6_len = sizeof(sockaddr_in6);
|
|
||||||
socketAddress->sin6_family = AF_INET6;
|
|
||||||
|
|
||||||
// address
|
|
||||||
memcpy(&socketAddress->sin6_addr, &address, sizeof(in6_addr));
|
|
||||||
if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// mask (/64)
|
|
||||||
memset(socketAddress->sin6_addr.s6_addr, 0xff, 8);
|
|
||||||
memset(socketAddress->sin6_addr.s6_addr + 8, 0, 8);
|
|
||||||
|
|
||||||
if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
AutoconfigLooper::_RemoveIPv6LinkLocal(int socket, const in6_addr &address)
|
|
||||||
{
|
|
||||||
struct ifreq request;
|
|
||||||
if (!prepare_request(request, fDevice.String()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
sockaddr_in6* socketAddress = (sockaddr_in6*)&request.ifr_addr;
|
|
||||||
socketAddress->sin6_len = sizeof(sockaddr_in6);
|
|
||||||
socketAddress->sin6_family = AF_INET6;
|
|
||||||
|
|
||||||
// address
|
|
||||||
memcpy(&socketAddress->sin6_addr, &address, sizeof(in6_addr));
|
|
||||||
if (ioctl(socket, SIOCDIFADDR, &request, sizeof(struct ifreq)) < 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif // INET6
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AutoconfigLooper::_ReadyToRun()
|
AutoconfigLooper::_ReadyToRun()
|
||||||
{
|
{
|
||||||
start_watching_network(B_WATCH_NETWORK_LINK_CHANGES, this);
|
start_watching_network(B_WATCH_NETWORK_LINK_CHANGES, this);
|
||||||
_ConfigureIPv4();
|
_ConfigureIPv4();
|
||||||
#ifdef INET6
|
//_ConfigureIPv6(); // TODO: router advertisement and dhcpv6
|
||||||
_ConfigureIPv6LinkLocal(true);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -296,10 +151,8 @@ AutoconfigLooper::MessageReceived(BMessage* message)
|
|||||||
if ((media & IFM_ACTIVE) != 0) {
|
if ((media & IFM_ACTIVE) != 0) {
|
||||||
// Reconfigure the interface when we have a link again
|
// Reconfigure the interface when we have a link again
|
||||||
_ConfigureIPv4();
|
_ConfigureIPv4();
|
||||||
|
//_ConfigureIPv6(); // TODO: router advertisement and dhcpv6
|
||||||
}
|
}
|
||||||
#ifdef INET6
|
|
||||||
_ConfigureIPv6LinkLocal((media & IFM_ACTIVE) != 0);
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -29,15 +29,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
void _RemoveClient();
|
void _RemoveClient();
|
||||||
void _ConfigureIPv4();
|
void _ConfigureIPv4();
|
||||||
void _ConfigureIPv6LinkLocal(bool add);
|
|
||||||
bool _AddIPv6LinkLocal(int socket, const in6_addr &);
|
|
||||||
void _RemoveIPv6LinkLocal(int socket, const in6_addr &);
|
|
||||||
void _ReadyToRun();
|
void _ReadyToRun();
|
||||||
|
|
||||||
BMessenger fTarget;
|
BMessenger fTarget;
|
||||||
BString fDevice;
|
BString fDevice;
|
||||||
AutoconfigClient* fCurrentClient;
|
AutoconfigClient* fCurrentClient;
|
||||||
uint8 fCurrentMac[6];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AUTOCONFIG_LOOPER_H
|
#endif // AUTOCONFIG_LOOPER_H
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_wlan ] : true ;
|
|||||||
#UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared libkernelppp headers ] ;
|
#UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared libkernelppp headers ] ;
|
||||||
#UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net DialUpPreflet ] ;
|
#UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net DialUpPreflet ] ;
|
||||||
|
|
||||||
#local defines = [ FDefines INET6=1 ] ;
|
|
||||||
|
|
||||||
SubDirCcFlags $(defines) ;
|
SubDirCcFlags $(defines) ;
|
||||||
SubDirC++Flags $(defines) ;
|
SubDirC++Flags $(defines) ;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
|
* Copyright 2006-2012, Haiku, Inc. All Rights Reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Axel Dörfler, [email protected]
|
* Axel Dörfler, [email protected]
|
||||||
* Vegard Wærp, [email protected]
|
* Vegard Wærp, [email protected]
|
||||||
|
* Alexander von Gluck, [email protected]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
@@ -79,6 +81,7 @@ private:
|
|||||||
BMessage* suggestedInterface = NULL);
|
BMessage* suggestedInterface = NULL);
|
||||||
void _ConfigureInterfaces(
|
void _ConfigureInterfaces(
|
||||||
BMessage* _missingDevice = NULL);
|
BMessage* _missingDevice = NULL);
|
||||||
|
void _ConfigureIPv6LinkLocal(const char* name);
|
||||||
void _BringUpInterfaces();
|
void _BringUpInterfaces();
|
||||||
void _StartServices();
|
void _StartServices();
|
||||||
status_t _HandleDeviceMonitor(BMessage* message);
|
status_t _HandleDeviceMonitor(BMessage* message);
|
||||||
@@ -105,13 +108,6 @@ struct address_family {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// AF_INET6 family
|
|
||||||
#if INET6
|
|
||||||
static bool inet6_parse_address(const char* string, sockaddr* address);
|
|
||||||
static void inet6_set_any_address(sockaddr* address);
|
|
||||||
static void inet6_set_port(sockaddr* address, int32 port);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const address_family kFamilies[] = {
|
static const address_family kFamilies[] = {
|
||||||
{
|
{
|
||||||
AF_INET,
|
AF_INET,
|
||||||
@@ -209,44 +205,6 @@ parse_address(int32& family, const char* argument, BNetworkAddress& address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if INET6
|
|
||||||
static bool
|
|
||||||
inet6_parse_address(const char* string, sockaddr* _address)
|
|
||||||
{
|
|
||||||
sockaddr_in6& address = *(sockaddr_in6*)_address;
|
|
||||||
|
|
||||||
if (inet_pton(AF_INET6, string, &address.sin6_addr) != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
address.sin6_family = AF_INET6;
|
|
||||||
address.sin6_len = sizeof(sockaddr_in6);
|
|
||||||
address.sin6_port = 0;
|
|
||||||
address.sin6_flowinfo = 0;
|
|
||||||
address.sin6_scope_id = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
inet6_set_any_address(sockaddr* _address)
|
|
||||||
{
|
|
||||||
sockaddr_in6& address = *(sockaddr_in6*)_address;
|
|
||||||
memset(&address, 0, sizeof(sockaddr_in6));
|
|
||||||
address.sin6_family = AF_INET6;
|
|
||||||
address.sin6_len = sizeof(struct sockaddr_in6);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
inet6_set_port(sockaddr* _address, int32 port)
|
|
||||||
{
|
|
||||||
sockaddr_in6& address = *(sockaddr_in6*)_address;
|
|
||||||
address.sin6_port = port;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -574,6 +532,9 @@ NetServer::_ConfigureInterface(BMessage& message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up IPv6 Link Local
|
||||||
|
_ConfigureIPv6LinkLocal(name);
|
||||||
|
|
||||||
BMessage addressMessage;
|
BMessage addressMessage;
|
||||||
for (int32 index = 0; message.FindMessage("address", index,
|
for (int32 index = 0; message.FindMessage("address", index,
|
||||||
&addressMessage) == B_OK; index++) {
|
&addressMessage) == B_OK; index++) {
|
||||||
@@ -619,7 +580,7 @@ NetServer::_ConfigureInterface(BMessage& message)
|
|||||||
if (addressMessage.FindString("broadcast", &string) == B_OK)
|
if (addressMessage.FindString("broadcast", &string) == B_OK)
|
||||||
parse_address(family, string, broadcast);
|
parse_address(family, string, broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoConfig) {
|
if (autoConfig) {
|
||||||
_QuitLooperForDevice(name);
|
_QuitLooperForDevice(name);
|
||||||
startAutoConfig = true;
|
startAutoConfig = true;
|
||||||
@@ -885,6 +846,86 @@ NetServer::_BringUpInterfaces()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
NetServer::_ConfigureIPv6LinkLocal(const char* name)
|
||||||
|
{
|
||||||
|
// Don't touch the loopback device
|
||||||
|
if (!strncmp(name, "loop", 4))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int socket = ::socket(AF_INET6, SOCK_DGRAM, 0);
|
||||||
|
if (socket < 0) {
|
||||||
|
// No ipv6 support, skip
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
close(socket);
|
||||||
|
|
||||||
|
BNetworkInterface interface(name);
|
||||||
|
BNetworkAddress link;
|
||||||
|
status_t result = interface.GetHardwareAddress(link);
|
||||||
|
if (result != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BString macString = link.ToString();
|
||||||
|
|
||||||
|
int32 macLength = macString.Length();
|
||||||
|
if (macLength != 17) {
|
||||||
|
syslog(LOG_DEBUG, "%s: MacAddress length (%" B_PRIu32 ") for interface"
|
||||||
|
" '%s' is invalid\n", __func__, macLength, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 mac[6];
|
||||||
|
char* macBuffer = macString.LockBuffer(macLength);
|
||||||
|
sscanf(macBuffer, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
|
||||||
|
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
|
||||||
|
macString.UnlockBuffer(macLength);
|
||||||
|
|
||||||
|
// Check for a few failure situations
|
||||||
|
static const char zeroMac[6] = {0, 0, 0, 0, 0, 0};
|
||||||
|
static const char fullMac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
if (memcmp(macBuffer, zeroMac, 6) == 0
|
||||||
|
|| memcmp(macBuffer, fullMac, 6) == 0) {
|
||||||
|
// Mac address is all 0 or all FF's
|
||||||
|
syslog(LOG_DEBUG, "%s: MacAddress for interface '%s' is invalid.",
|
||||||
|
__func__, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a Link Local Scope address
|
||||||
|
// (IPv6 address based on Mac address)
|
||||||
|
in6_addr addressRaw;
|
||||||
|
memset(addressRaw.s6_addr, 0, sizeof(addressRaw.s6_addr));
|
||||||
|
addressRaw.s6_addr[0] = 0xfe;
|
||||||
|
addressRaw.s6_addr[1] = 0x80;
|
||||||
|
addressRaw.s6_addr[8] = mac[0] ^ 0x02;
|
||||||
|
addressRaw.s6_addr[9] = mac[1];
|
||||||
|
addressRaw.s6_addr[10] = mac[2];
|
||||||
|
addressRaw.s6_addr[11] = 0xff;
|
||||||
|
addressRaw.s6_addr[12] = 0xfe;
|
||||||
|
addressRaw.s6_addr[13] = mac[3];
|
||||||
|
addressRaw.s6_addr[14] = mac[4];
|
||||||
|
addressRaw.s6_addr[15] = mac[5];
|
||||||
|
|
||||||
|
BNetworkAddress localLinkAddress(addressRaw, 0);
|
||||||
|
BNetworkAddress localLinkMask("ffff:ffff:ffff:ffff::"); // 64
|
||||||
|
BNetworkAddress localLinkBroadcast("fe80::ffff:ffff:ffff:ffff");
|
||||||
|
|
||||||
|
BNetworkInterfaceAddress interfaceAddress;
|
||||||
|
interfaceAddress.SetAddress(localLinkAddress);
|
||||||
|
interfaceAddress.SetMask(localLinkMask);
|
||||||
|
interfaceAddress.SetBroadcast(localLinkMask);
|
||||||
|
|
||||||
|
/* TODO: Duplicate Address Detection. (DAD)
|
||||||
|
Need to blast an icmp packet over the IPv6 network from :: to ensure
|
||||||
|
there aren't duplicate MAC addresses on the network. (definitely an
|
||||||
|
edge case, but a possible issue)
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface.AddAddress(interfaceAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
NetServer::_StartServices()
|
NetServer::_StartServices()
|
||||||
{
|
{
|
||||||
@@ -910,12 +951,12 @@ NetServer::_HandleDeviceMonitor(BMessage* message)
|
|||||||
// not a device entry, ignore
|
// not a device entry, ignore
|
||||||
return B_NAME_NOT_FOUND;
|
return B_NAME_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode == B_ENTRY_CREATED)
|
if (opcode == B_ENTRY_CREATED)
|
||||||
_ConfigureDevice(path);
|
_ConfigureDevice(path);
|
||||||
else
|
else
|
||||||
_RemoveInterface(path);
|
_RemoveInterface(path);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user