1/*
2 * Copyright 2006-2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel Dörfler, axeld@pinc-software.de
7 *		Alexander von Gluck, kallisti5@unixzen.com
8 */
9
10
11#include "AutoconfigLooper.h"
12
13#include <errno.h>
14#include <net/if_dl.h>
15#include <net/if_media.h>
16#include <net/if_types.h>
17#include <stdio.h>
18#include <sys/socket.h>
19#include <sys/sockio.h>
20
21#include <NetworkInterface.h>
22#include <NetworkNotifications.h>
23
24#include "DHCPClient.h"
25#include "NetServer.h"
26
27
28static const uint32 kMsgReadyToRun = 'rdyr';
29
30
31AutoconfigLooper::AutoconfigLooper(BMessenger target, const char* device)
32	: BLooper(device),
33	fTarget(target),
34	fDevice(device),
35	fCurrentClient(NULL),
36	fLastMediaStatus(0)
37{
38	BMessage ready(kMsgReadyToRun);
39	PostMessage(&ready);
40}
41
42
43AutoconfigLooper::~AutoconfigLooper()
44{
45}
46
47
48void
49AutoconfigLooper::_RemoveClient()
50{
51	if (fCurrentClient == NULL)
52		return;
53
54	RemoveHandler(fCurrentClient);
55	delete fCurrentClient;
56	fCurrentClient = NULL;
57}
58
59
60void
61AutoconfigLooper::_ConfigureIPv4()
62{
63	// start with DHCP
64
65	if (fCurrentClient == NULL) {
66		fCurrentClient = new DHCPClient(fTarget, fDevice.String());
67		AddHandler(fCurrentClient);
68	}
69
70	// set IFF_CONFIGURING flag on interface
71
72	BNetworkInterface interface(fDevice.String());
73	int32 flags = interface.Flags() & ~IFF_AUTO_CONFIGURED;
74	interface.SetFlags(flags | IFF_CONFIGURING);
75
76	if (fCurrentClient->Initialize() == B_OK)
77		return;
78
79	_RemoveClient();
80
81	puts("DHCP failed miserably!");
82
83	// DHCP obviously didn't work out, take some default values for now
84	// TODO: have a look at zeroconf
85	// TODO: this could also be done add-on based
86
87	if ((interface.Flags() & IFF_CONFIGURING) == 0) {
88		// Someone else configured the interface in the mean time
89		return;
90	}
91
92	BMessage message(kMsgConfigureInterface);
93	message.AddString("device", fDevice.String());
94	message.AddBool("auto_configured", true);
95
96	BNetworkAddress link;
97	uint8 last = 56;
98	if (interface.GetHardwareAddress(link) == B_OK) {
99		// choose IP address depending on the MAC address, if available
100		uint8* mac = link.LinkLevelAddress();
101		last = mac[0] ^ mac[1] ^ mac[2] ^ mac[3] ^ mac[4] ^ mac[5];
102		if (last > 253)
103			last = 253;
104		else if (last == 0)
105			last = 1;
106	}
107
108	// IANA defined the default autoconfig network (for when a DHCP request
109	// fails for some reason) as being 169.254.0.0/255.255.0.0. We are only
110	// generating the last octet but we could also use the 2 last octets if
111	// wanted.
112	char string[64];
113	snprintf(string, sizeof(string), "169.254.0.%u", last);
114
115	BMessage address;
116	address.AddInt32("family", AF_INET);
117	address.AddString("address", string);
118	message.AddMessage("address", &address);
119
120	fTarget.SendMessage(&message);
121}
122
123
124void
125AutoconfigLooper::_ReadyToRun()
126{
127	start_watching_network(B_WATCH_NETWORK_LINK_CHANGES, this);
128	_ConfigureIPv4();
129	//_ConfigureIPv6();	// TODO: router advertisement and dhcpv6
130}
131
132
133void
134AutoconfigLooper::MessageReceived(BMessage* message)
135{
136	switch (message->what) {
137		case kMsgReadyToRun:
138			_ReadyToRun();
139			break;
140
141		case B_NETWORK_MONITOR:
142			const char* device;
143			int32 opcode;
144			int32 media;
145			if (message->FindInt32("opcode", &opcode) != B_OK
146				|| opcode != B_NETWORK_DEVICE_LINK_CHANGED
147				|| message->FindString("device", &device) != B_OK
148				|| fDevice != device
149				|| message->FindInt32("media", &media) != B_OK)
150				break;
151
152			if ((fLastMediaStatus & IFM_ACTIVE) == 0
153				&& (media & IFM_ACTIVE) != 0) {
154				// Reconfigure the interface when we have a link again
155				_ConfigureIPv4();
156				//_ConfigureIPv6();	// TODO: router advertisement and dhcpv6
157			}
158			fLastMediaStatus = media;
159			break;
160
161		default:
162			BLooper::MessageReceived(message);
163			break;
164	}
165}
166
167