xref: /haiku/src/servers/net/AutoconfigLooper.cpp (revision 4b3b81da9e459443d75329cfd08bc9a57ad02653)
1 /*
2  * Copyright 2006-2007, 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  */
8 
9 
10 #include "AutoconfigLooper.h"
11 #include "DHCPClient.h"
12 #include "NetServer.h"
13 
14 #include <errno.h>
15 #include <net/if_dl.h>
16 #include <net/if_types.h>
17 #include <stdio.h>
18 #include <sys/socket.h>
19 #include <sys/sockio.h>
20 
21 
22 static const uint32 kMsgReadyToRun = 'rdyr';
23 
24 
25 AutoconfigLooper::AutoconfigLooper(BMessenger target, const char* device)
26 	: BLooper(device),
27 	fTarget(target),
28 	fDevice(device)
29 {
30 	BMessage ready(kMsgReadyToRun);
31 	PostMessage(&ready);
32 }
33 
34 
35 AutoconfigLooper::~AutoconfigLooper()
36 {
37 }
38 
39 
40 void
41 AutoconfigLooper::_ReadyToRun()
42 {
43 	ifreq request;
44 	if (!prepare_request(request, fDevice.String()))
45 		return;
46 
47 	// set IFF_CONFIGURING flag on interface
48 
49 	int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
50 	if (socket < 0)
51 		return;
52 
53 	if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) == 0) {
54 		request.ifr_flags |= IFF_CONFIGURING;
55 		ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq));
56 	}
57 
58 	close(socket);
59 
60 	// start with DHCP
61 
62 	DHCPClient* client = new DHCPClient(fTarget, fDevice.String());
63 	AddHandler(client);
64 
65 	if (client->Initialize() == B_OK)
66 		return;
67 
68 	RemoveHandler(client);
69 	delete client;
70 
71 	puts("DHCP failed miserably!");
72 
73 	// DHCP obviously didn't work out, take some default values for now
74 	// TODO: have a look at zeroconf
75 	// TODO: this could also be done add-on based
76 
77 	BMessage interface(kMsgConfigureInterface);
78 	interface.AddString("device", fDevice.String());
79 	interface.AddBool("auto", true);
80 
81 	uint8 mac[6];
82 	uint8 last = 56;
83 	if (get_mac_address(fDevice.String(), mac) == B_OK) {
84 		// choose IP address depending on the MAC address, if available
85 		last = mac[0] ^ mac[1] ^ mac[2] ^ mac[3] ^ mac[4] ^ mac[5];
86 		if (last > 253)
87 			last = 253;
88 		else if (last == 0)
89 			last = 1;
90 	}
91 
92 	char string[64];
93 	// IANA defined the default autoconfig network (for when a DHCP request
94 	// fails for some reason) as being 169.254.0.0/255.255.0.0. We are only
95 	// generating the last octet but we could also use the 2 last octets if
96 	// wanted.
97 	snprintf(string, sizeof(string), "169.254.0.%u", last);
98 
99 	BMessage address;
100 	address.AddString("family", "inet");
101 	address.AddString("address", string);
102 	interface.AddMessage("address", &address);
103 
104 	fTarget.SendMessage(&interface);
105 }
106 
107 
108 void
109 AutoconfigLooper::MessageReceived(BMessage* message)
110 {
111 	switch (message->what) {
112 		case kMsgReadyToRun:
113 			_ReadyToRun();
114 			break;
115 
116 		default:
117 			BLooper::MessageReceived(message);
118 			break;
119 	}
120 }
121 
122