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