2 * Copyright 2006-2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
7 * Alexander von Gluck, kallisti5@unixzen.com
11 #include "AutoconfigLooper.h"
14 #include <net/if_dl.h>
15 #include <net/if_media.h>
16 #include <net/if_types.h>
18 #include <sys/socket.h>
19 #include <sys/sockio.h>
21 #include <NetworkInterface.h>
22 #include <NetworkNotifications.h>
24 #include "DHCPClient.h"
25 #include "NetServer.h"
28 static const uint32 kMsgReadyToRun
= 'rdyr';
31 AutoconfigLooper::AutoconfigLooper(BMessenger target
, const char* device
)
37 fJoiningNetwork(false)
39 BMessage
ready(kMsgReadyToRun
);
44 AutoconfigLooper::~AutoconfigLooper()
50 AutoconfigLooper::_RemoveClient()
52 if (fCurrentClient
== NULL
)
55 RemoveHandler(fCurrentClient
);
56 delete fCurrentClient
;
57 fCurrentClient
= NULL
;
62 AutoconfigLooper::_ConfigureIPv4()
66 if (fCurrentClient
== NULL
) {
67 fCurrentClient
= new DHCPClient(fTarget
, fDevice
.String());
68 AddHandler(fCurrentClient
);
71 // set IFF_CONFIGURING flag on interface
73 BNetworkInterface
interface(fDevice
.String());
74 int32 flags
= interface
.Flags() & ~IFF_AUTO_CONFIGURED
;
75 interface
.SetFlags(flags
| IFF_CONFIGURING
);
77 if (fCurrentClient
->Initialize() == B_OK
)
82 puts("DHCP failed miserably!");
84 // DHCP obviously didn't work out, take some default values for now
85 // TODO: have a look at zeroconf
86 // TODO: this could also be done add-on based
88 if ((interface
.Flags() & IFF_CONFIGURING
) == 0) {
89 // Someone else configured the interface in the mean time
93 BMessage
message(kMsgConfigureInterface
);
94 message
.AddString("device", fDevice
.String());
95 message
.AddBool("auto_configured", true);
99 if (interface
.GetHardwareAddress(link
) == B_OK
) {
100 // choose IP address depending on the MAC address, if available
101 uint8
* mac
= link
.LinkLevelAddress();
102 last
= mac
[0] ^ mac
[1] ^ mac
[2] ^ mac
[3] ^ mac
[4] ^ mac
[5];
109 // IANA defined the default autoconfig network (for when a DHCP request
110 // fails for some reason) as being 169.254.0.0/255.255.0.0. We are only
111 // generating the last octet but we could also use the 2 last octets if
114 snprintf(string
, sizeof(string
), "169.254.0.%u", last
);
117 address
.AddInt32("family", AF_INET
);
118 address
.AddString("address", string
);
119 message
.AddMessage("address", &address
);
121 fTarget
.SendMessage(&message
);
126 AutoconfigLooper::_ReadyToRun()
128 start_watching_network(
129 B_WATCH_NETWORK_LINK_CHANGES
| B_WATCH_NETWORK_WLAN_CHANGES
, this);
131 BNetworkInterface
interface(fDevice
.String());
132 if (interface
.HasLink()) {
134 //_ConfigureIPv6(); // TODO: router advertisement and dhcpv6
136 // Also make sure we don't spuriously try to configure again from
137 // a link changed notification that might race us.
138 fLastMediaStatus
|= IFM_ACTIVE
;
144 AutoconfigLooper::_NetworkMonitorNotification(BMessage
* message
)
148 if (message
->FindString("device", &device
) != B_OK
) {
149 if (message
->FindString("interface", &device
) != B_OK
)
152 // TODO: Clean this mess up. Wireless devices currently use their
153 // "device_name" in the interface field. First of all the
154 // joins/leaves/scans should be device, not interface specific, so
155 // the field should be changed. Then the device_name as seen by the
156 // driver is missing the "/dev" part, as it is a relative path within
157 // "/dev". On the other hand the net stack uses names that include
158 // "/dev" as it uses them to open the fds, hence a full absolute path.
159 // Note that the wpa_supplicant does the same workaround as we do here
160 // to build an interface name, so that has to be changed as well when
162 device
.Prepend("/dev/");
165 if (device
!= fDevice
|| message
->FindInt32("opcode", &opcode
) != B_OK
)
169 case B_NETWORK_DEVICE_LINK_CHANGED
:
172 if (message
->FindInt32("media", &media
) != B_OK
)
175 if ((fLastMediaStatus
& IFM_ACTIVE
) == 0
176 && (media
& IFM_ACTIVE
) != 0) {
177 // Reconfigure the interface when we have a link again
179 //_ConfigureIPv6(); // TODO: router advertisement and dhcpv6
182 fLastMediaStatus
= media
;
186 case B_NETWORK_WLAN_SCANNED
:
188 if (fJoiningNetwork
|| (fLastMediaStatus
& IFM_ACTIVE
) != 0) {
189 // We already have a link or are already joining.
193 fJoiningNetwork
= true;
194 // TODO: For now we never reset this flag. We can only do that
195 // after infrastructure has been added to discern a scan reason.
196 // If we would always auto join we would possibly interfere
197 // with active scans in the process of connecting to an AP
198 // either for the initial connection, or after connection loss
199 // to re-establish the link.
201 BMessage
message(kMsgAutoJoinNetwork
);
202 message
.AddString("device", fDevice
);
203 fTarget
.SendMessage(&message
);
211 AutoconfigLooper::MessageReceived(BMessage
* message
)
213 switch (message
->what
) {
218 case B_NETWORK_MONITOR
:
219 _NetworkMonitorNotification(message
);
223 BLooper::MessageReceived(message
);