1 //----------------------------------------------------------------------- 2 // This software is part of the OpenBeOS distribution and is covered 3 // by the OpenBeOS license. 4 // 5 // Copyright (c) 2003-2004 Waldemar Kornewald, Waldemar.Kornewald@web.de 6 //----------------------------------------------------------------------- 7 8 #include <KernelExport.h> 9 #include <driver_settings.h> 10 #include <core_funcs.h> 11 #include <net_module.h> 12 13 #include <ethernet_module.h> 14 15 #include <KPPPInterface.h> 16 #include <KPPPModule.h> 17 #include <KPPPUtils.h> 18 #include <LockerHelper.h> 19 20 #include "PPPoEDevice.h" 21 #include "DiscoveryPacket.h" 22 23 24 typedef struct pppoe_query { 25 ifnet *ethernetIfnet; 26 uint32 hostUniq; 27 thread_id receiver; 28 } pppoe_query; 29 30 #define PPPoE_MODULE_NAME NETWORK_MODULES_ROOT "ppp/pppoe" 31 32 struct core_module_info *core = NULL; 33 static struct ethernet_module_info *sEthernet; 34 static int32 sHostUniq = 0; 35 status_t std_ops(int32 op, ...); 36 37 static BLocker sLock; 38 static TemplateList<PPPoEDevice*> *sDevices; 39 static TemplateList<pppoe_query*> *sQueries; 40 41 42 static 43 void 44 SendQueryPacket(pppoe_query *query, DiscoveryPacket& discovery) 45 { 46 char data[PPPoE_QUERY_REPORT_SIZE]; 47 uint32 position = sizeof(uint32); 48 pppoe_tag *acName = discovery.TagWithType(AC_NAME); 49 50 if(acName) { 51 if(acName->length >= PPPoE_QUERY_REPORT_SIZE) 52 return; 53 54 memcpy(data + position, acName->data, acName->length); 55 position += acName->length; 56 } 57 58 data[position++] = 0; 59 60 pppoe_tag *tag; 61 for(int32 index = 0; index < discovery.CountTags(); index++) { 62 tag = discovery.TagAt(index); 63 if(tag && tag->type == SERVICE_NAME) { 64 if(position + tag->length >= PPPoE_QUERY_REPORT_SIZE) 65 return; 66 67 memcpy(data + position, tag->data, tag->length); 68 position += tag->length; 69 data[position++] = 0; 70 } 71 } 72 73 memcpy(data, &position, sizeof(uint32)); 74 // add the total length 75 76 send_data_with_timeout(query->receiver, PPPoE_QUERY_REPORT, data, 77 PPPoE_QUERY_REPORT_SIZE, 700000); 78 } 79 80 81 ifnet* 82 FindPPPoEInterface(const char *name) 83 { 84 if(!name) 85 return NULL; 86 87 ifnet *current = get_interfaces(); 88 for(; current; current = current->if_next) { 89 if(current->if_type == IFT_ETHER && current->if_name 90 && !strcmp(current->if_name, name)) 91 return current; 92 } 93 94 return NULL; 95 } 96 97 uint32 98 NewHostUniq() 99 { 100 return (uint32) atomic_add(&sHostUniq, 1); 101 } 102 103 104 void 105 add_device(PPPoEDevice *device) 106 { 107 #if DEBUG 108 dprintf("PPPoE: add_device()\n"); 109 #endif 110 111 LockerHelper locker(sLock); 112 sDevices->AddItem(device); 113 } 114 115 116 void 117 remove_device(PPPoEDevice *device) 118 { 119 #if DEBUG 120 dprintf("PPPoE: remove_device()\n"); 121 #endif 122 123 LockerHelper locker(sLock); 124 sDevices->RemoveItem(device); 125 } 126 127 128 static 129 void 130 pppoe_input(struct mbuf *packet) 131 { 132 if(!packet) 133 return; 134 135 ifnet *sourceIfnet = packet->m_pkthdr.rcvif; 136 complete_pppoe_header *header = mtod(packet, complete_pppoe_header*); 137 PPPoEDevice *device; 138 pppoe_query *query; 139 140 LockerHelper locker(sLock); 141 142 if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOEDISC 143 && header->pppoeHeader.length <= PPPoE_QUERY_REPORT_SIZE) { 144 for(int32 index = 0; index < sDevices->CountItems(); index++) { 145 query = sQueries->ItemAt(index); 146 147 if(query && query->ethernetIfnet == sourceIfnet) { 148 if(header->pppoeHeader.code == PADO) { 149 DiscoveryPacket discovery(packet, ETHER_HDR_LEN); 150 if(discovery.InitCheck() != B_OK) { 151 dprintf("PPPoE: received corrupted discovery packet!\n"); 152 m_freem(packet); 153 return; 154 } 155 156 pppoe_tag *hostTag = discovery.TagWithType(HOST_UNIQ); 157 if(hostTag && hostTag->length == 4 158 && *((uint32*)hostTag->data) == query->hostUniq) { 159 SendQueryPacket(query, discovery); 160 m_freem(packet); 161 return; 162 } 163 } 164 } 165 } 166 } 167 168 for(int32 index = 0; index < sDevices->CountItems(); index++) { 169 device = sDevices->ItemAt(index); 170 171 if(device && device->EthernetIfnet() == sourceIfnet) { 172 if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOE 173 && header->pppoeHeader.sessionID == device->SessionID()) { 174 #if DEBUG 175 dprintf("PPPoE: session packet\n"); 176 #endif 177 device->Receive(packet); 178 return; 179 } else if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOEDISC 180 && header->pppoeHeader.code != PADI 181 && header->pppoeHeader.code != PADR 182 && !device->IsDown()) { 183 #if DEBUG 184 dprintf("PPPoE: discovery packet\n"); 185 #endif 186 DiscoveryPacket discovery(packet, ETHER_HDR_LEN); 187 if(discovery.InitCheck() != B_OK) { 188 dprintf("PPPoE: received corrupted discovery packet!\n"); 189 m_freem(packet); 190 return; 191 } 192 193 pppoe_tag *tag = discovery.TagWithType(HOST_UNIQ); 194 if(header->pppoeHeader.code == PADT || (tag && tag->length == 4 195 && *((uint32*)tag->data) == device->HostUniq())) { 196 device->Receive(packet); 197 return; 198 } 199 } 200 } 201 } 202 203 dprintf("PPPoE: No device found for packet from: %s\n", sourceIfnet->if_name); 204 m_freem(packet); 205 } 206 207 208 static 209 bool 210 add_to(KPPPInterface& mainInterface, KPPPInterface *subInterface, 211 driver_parameter *settings, ppp_module_key_type type) 212 { 213 if(mainInterface.Mode() != PPP_CLIENT_MODE || type != PPP_DEVICE_KEY_TYPE) 214 return B_ERROR; 215 216 PPPoEDevice *device; 217 bool success; 218 if(subInterface) { 219 device = new PPPoEDevice(*subInterface, settings); 220 success = subInterface->SetDevice(device); 221 } else { 222 device = new PPPoEDevice(mainInterface, settings); 223 success = mainInterface.SetDevice(device); 224 } 225 226 #if DEBUG 227 dprintf("PPPoE: add_to(): %s\n", 228 success && device && device->InitCheck() == B_OK ? "OK" : "ERROR"); 229 #endif 230 231 return success && device && device->InitCheck() == B_OK; 232 } 233 234 235 static 236 status_t 237 control(uint32 op, void *data, size_t length) 238 { 239 switch(op) { 240 case PPPoE_GET_INTERFACES: { 241 int32 position = 0, count = 0; 242 char *names = (char*) data; 243 244 ifnet *current = get_interfaces(); 245 for(; current; current = current->if_next) { 246 if(current->if_type == IFT_ETHER && current->if_name) { 247 if(position + strlen(current->if_name) + 1 > length) 248 return B_NO_MEMORY; 249 250 strcpy(names + position, current->if_name); 251 position += strlen(current->if_name); 252 names[position++] = 0; 253 ++count; 254 } 255 } 256 257 return count; 258 } 259 260 case PPPoE_QUERY_SERVICES: { 261 // XXX: as all modules are loaded on-demand we must wait for the results 262 263 if(!data || length != sizeof(pppoe_query_request)) 264 return B_ERROR; 265 266 pppoe_query_request *request = (pppoe_query_request*) data; 267 268 pppoe_query query; 269 query.ethernetIfnet = FindPPPoEInterface(request->interfaceName); 270 if(!query.ethernetIfnet) 271 return B_BAD_VALUE; 272 273 query.hostUniq = NewHostUniq(); 274 query.receiver = request->receiver; 275 276 sLock.Lock(); 277 sQueries->AddItem(&query); 278 sLock.Unlock(); 279 280 snooze(2000000); 281 // wait two seconds for results 282 283 sLock.Lock(); 284 sQueries->RemoveItem(&query); 285 sLock.Unlock(); 286 } break; 287 288 default: 289 return B_ERROR; 290 } 291 292 return B_OK; 293 } 294 295 296 static ppp_module_info pppoe_module = { 297 { 298 PPPoE_MODULE_NAME, 299 0, 300 std_ops 301 }, 302 control, 303 add_to 304 }; 305 306 307 _EXPORT 308 status_t 309 std_ops(int32 op, ...) 310 { 311 switch(op) { 312 case B_MODULE_INIT: 313 if(get_module(NET_CORE_MODULE_NAME, (module_info**)&core) != B_OK) 314 return B_ERROR; 315 316 if(get_module(NET_ETHERNET_MODULE_NAME, 317 (module_info**) &sEthernet) != B_OK) { 318 put_module(NET_CORE_MODULE_NAME); 319 return B_ERROR; 320 } 321 322 set_max_linkhdr(PPPoE_HEADER_SIZE + ETHER_HDR_LEN); 323 sDevices = new TemplateList<PPPoEDevice*>; 324 sQueries = new TemplateList<pppoe_query*>; 325 sEthernet->set_pppoe_receiver(pppoe_input); 326 327 #if DEBUG 328 dprintf("PPPoE: Registered PPPoE receiver.\n"); 329 #endif 330 return B_OK; 331 332 case B_MODULE_UNINIT: 333 delete sDevices; 334 sEthernet->unset_pppoe_receiver(); 335 #if DEBUG 336 dprintf("PPPoE: Unregistered PPPoE receiver.\n"); 337 #endif 338 put_module(NET_CORE_MODULE_NAME); 339 put_module(NET_ETHERNET_MODULE_NAME); 340 break; 341 342 default: 343 return B_ERROR; 344 } 345 346 return B_OK; 347 } 348 349 350 _EXPORT 351 module_info *modules[] = { 352 (module_info*) &pppoe_module, 353 NULL 354 }; 355