1 /* 2 * Copyright 2003-2006, Waldemar Kornewald <wkornew@gmx.net> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <KernelExport.h> 7 #include <driver_settings.h> 8 9 #include <lock.h> 10 #include <util/AutoLock.h> 11 #include <ByteOrder.h> 12 13 #include <net/if_types.h> 14 #include <net/if_dl.h> 15 #include <net/if.h> 16 #include <sys/sockio.h> 17 18 #include <net_buffer.h> 19 #include <net_datalink.h> // for get_interface and control 20 #include <net_stack.h> 21 #include <NetBufferUtilities.h> 22 23 #include <KPPPInterface.h> 24 #include <KPPPModule.h> 25 #include <KPPPUtils.h> 26 27 #include "PPPoEDevice.h" 28 #include "DiscoveryPacket.h" 29 30 31 typedef struct pppoe_query { 32 net_device *ethernetIfnet; 33 uint32 hostUniq; 34 thread_id receiver; 35 } pppoe_query; 36 37 #define PPPoE_MODULE_NAME "network/ppp/pppoe" 38 39 net_stack_module_info *gStackModule = NULL; 40 net_buffer_module_info *gBufferModule = NULL; 41 net_datalink_module_info *sDatalinkModule = NULL; 42 43 static int32 sHostUniq = 0; 44 status_t std_ops(int32 op, ...); 45 46 // static mutex sLock("PPPoEList"); 47 48 static TemplateList<PPPoEDevice*> *sDevices; 49 static TemplateList<pppoe_query*> *sQueries; 50 51 52 static 53 void 54 SendQueryPacket(pppoe_query *query, DiscoveryPacket& discovery) 55 { 56 char data[PPPoE_QUERY_REPORT_SIZE]; 57 uint32 position = sizeof(uint32); 58 pppoe_tag *acName = discovery.TagWithType(AC_NAME); 59 60 if (acName) { 61 if (acName->length >= PPPoE_QUERY_REPORT_SIZE) 62 return; 63 64 memcpy(data + position, acName->data, acName->length); 65 position += acName->length; 66 } 67 68 data[position++] = 0; 69 70 pppoe_tag *tag; 71 for (int32 index = 0; index < discovery.CountTags(); index++) { 72 tag = discovery.TagAt(index); 73 if (tag && tag->type == SERVICE_NAME) { 74 if (position + tag->length >= PPPoE_QUERY_REPORT_SIZE) 75 return; 76 77 memcpy(data + position, tag->data, tag->length); 78 position += tag->length; 79 data[position++] = 0; 80 } 81 } 82 83 memcpy(data, &position, sizeof(uint32)); 84 // add the total length 85 86 send_data_with_timeout(query->receiver, PPPoE_QUERY_REPORT, data, 87 PPPoE_QUERY_REPORT_SIZE, 700000); 88 } 89 90 91 net_interface * 92 get_interface_by_name(net_domain *domain, const char *name) 93 { 94 ifreq request; 95 memset(&request, 0, sizeof(request)); 96 size_t size = sizeof(request); 97 98 strlcpy(request.ifr_name, name, IF_NAMESIZE); 99 100 if (sDatalinkModule->control(domain, SIOCGIFINDEX, &request, &size) != B_OK) { 101 TRACE("sDatalinkModule->control failure\n"); 102 return NULL; 103 } 104 return sDatalinkModule->get_interface(domain, request.ifr_index); 105 } 106 107 108 net_device* 109 FindPPPoEInterface(const char *name) 110 { 111 if (!name) 112 return NULL; 113 114 net_interface* ethernetInterfaceOfPPPOE = NULL; 115 net_domain* domain = NULL; 116 117 domain = gStackModule->get_domain(AF_INET); 118 ethernetInterfaceOfPPPOE = get_interface_by_name(domain, name); 119 120 if (ethernetInterfaceOfPPPOE == NULL) { 121 TRACE("get_interface_by_name can not find eth\n"); 122 return NULL; 123 } 124 125 if (ethernetInterfaceOfPPPOE->device) 126 return ethernetInterfaceOfPPPOE->device; 127 128 return NULL; 129 } 130 131 132 uint32 133 NewHostUniq() 134 { 135 return (uint32) atomic_add(&sHostUniq, 1); 136 } 137 138 139 void 140 add_device(PPPoEDevice *device) 141 { 142 TRACE("PPPoE: add_device()\n"); 143 144 // MutexLocker locker(sLock); 145 if (!sDevices->HasItem(device)) 146 sDevices->AddItem(device); 147 } 148 149 150 void 151 remove_device(PPPoEDevice *device) 152 { 153 TRACE("PPPoE: remove_device()\n"); 154 155 // MutexLocker locker(sLock); 156 sDevices->RemoveItem(device); 157 } 158 159 160 status_t 161 pppoe_input(void *cookie, net_device *_device, net_buffer *packet) 162 { 163 if (!packet) 164 return B_ERROR; 165 166 NetBufferHeaderReader<pppoe_header> bufferheader(packet); 167 if (bufferheader.Status() != B_OK) 168 return B_ERROR; 169 170 pppoe_header &header = bufferheader.Data(); 171 172 // remove the following lines when pppoe server is enabled 173 if (header.code == PADI) { 174 TRACE("PADI packet received, ignoreing!\n"); 175 gBufferModule->free(packet); 176 return B_OK; 177 } 178 179 if (header.code == PADO || header.code == PADR || header.code == PADS || header.code == PADT) 180 { 181 uint8 peerEtherAddr[ETHER_ADDRESS_LENGTH]; 182 struct sockaddr_dl& source = *(struct sockaddr_dl*)packet->source; 183 memcpy(peerEtherAddr, source.sdl_data, ETHER_ADDRESS_LENGTH); 184 const char *str = header.code == PADI ? "PADI" : 185 header.code == PADO ? "PADO" : 186 header.code == PADR ? "PADR" : 187 header.code == PADS ? "PADS" : 188 "PADT" ; 189 190 dprintf("%s from:%02x:%02x:%02x:%02x:%02x:%02x code:%02x\n", str, 191 peerEtherAddr[0], peerEtherAddr[1], peerEtherAddr[2], 192 peerEtherAddr[3], peerEtherAddr[4], peerEtherAddr[5], 193 header.code); 194 } 195 196 PPPoEDevice *device; 197 pppoe_query *query; 198 199 sockaddr_dl& linkAddress = *(sockaddr_dl*)packet->source; 200 int32 specificType = B_NET_FRAME_TYPE(linkAddress.sdl_type, 201 ntohs(linkAddress.sdl_e_type)); 202 203 // MutexLocker locker(sLock); 204 205 if (specificType == B_NET_FRAME_TYPE_PPPOE_DISCOVERY 206 && ntohs(header.length) <= PPPoE_QUERY_REPORT_SIZE) { 207 for (int32 index = 0; index < sDevices->CountItems(); index++) { 208 query = sQueries->ItemAt(index); 209 210 if (query) {// && query->ethernetIfnet == sourceIfnet) { 211 if (header.code == PADO) { 212 DiscoveryPacket discovery(packet, ETHER_HDR_LEN); 213 if (discovery.InitCheck() != B_OK) { 214 ERROR("PPPoE: received corrupted discovery packet!\n"); 215 // gBufferModule->free(packet); 216 return B_ERROR; 217 } 218 219 pppoe_tag *hostTag = discovery.TagWithType(HOST_UNIQ); 220 if (hostTag && hostTag->length == 4 221 && *((uint32*)hostTag->data) == query->hostUniq) { 222 SendQueryPacket(query, discovery); 223 // gBufferModule->free(packet); 224 return B_ERROR; 225 } 226 } 227 } 228 } 229 } 230 231 TRACE("in pppoed processing sDevices->CountItems(): %ld\n", sDevices->CountItems()); 232 233 for (int32 index = 0; index < sDevices->CountItems(); index++) { 234 device = sDevices->ItemAt(index); 235 236 TRACE("device->SessionID() %d, header.sessionID: %d\n", device->SessionID(), 237 header.sessionID); 238 239 if (device) { // && device->EthernetIfnet() == sourceIfnet) { 240 if (specificType == B_NET_FRAME_TYPE_PPPOE 241 && header.sessionID == device->SessionID()) { 242 TRACE("PPPoE: session packet\n"); 243 device->Receive(packet); 244 return B_OK; 245 } 246 247 if (specificType == B_NET_FRAME_TYPE_PPPOE_DISCOVERY 248 && header.code != PADI 249 && header.code != PADR 250 && !device->IsDown()) { 251 TRACE("PPPoE: discovery packet\n"); 252 253 DiscoveryPacket discovery(packet, ETHER_HDR_LEN); 254 if (discovery.InitCheck() != B_OK) { 255 ERROR("PPPoE: received corrupted discovery packet!\n"); 256 gBufferModule->free(packet); 257 return B_OK; 258 } 259 260 pppoe_tag *tag = discovery.TagWithType(HOST_UNIQ); 261 if (header.code == PADT || (tag && tag->length == 4 262 && *((uint32*)tag->data) == device->HostUniq())) { 263 device->Receive(packet); 264 return B_OK; 265 } 266 } 267 } 268 } 269 270 ERROR("PPPoE: No device found for packet from: %s\n", "ethernet"); 271 // gBufferModule->free(packet); 272 return B_ERROR; 273 } 274 275 276 static 277 bool 278 add_to(KPPPInterface& mainInterface, KPPPInterface *subInterface, 279 driver_parameter *settings, ppp_module_key_type type) 280 { 281 if (mainInterface.Mode() != PPP_CLIENT_MODE || type != PPP_DEVICE_KEY_TYPE) 282 return B_ERROR; 283 284 PPPoEDevice *device; 285 bool success; 286 if (subInterface) { 287 device = new PPPoEDevice(*subInterface, settings); 288 success = subInterface->SetDevice(device); 289 } else { 290 device = new PPPoEDevice(mainInterface, settings); 291 success = mainInterface.SetDevice(device); 292 } 293 294 TRACE("PPPoE: add_to(): %s\n", 295 success && device && device->InitCheck() == B_OK ? "OK" : "ERROR"); 296 297 return success && device && device->InitCheck() == B_OK; 298 } 299 300 301 static 302 status_t 303 control(uint32 op, void *data, size_t length) 304 { 305 switch (op) { 306 case PPPoE_GET_INTERFACES: { 307 int32 position = 0, count = 0; 308 char *names = (char*) data; 309 310 net_device *current = NULL; // get_interfaces(); 311 for (; current; current = NULL) { 312 if (current->type == IFT_ETHER && current->name) { 313 if (position + strlen(current->name) + 1 > length) 314 return B_NO_MEMORY; 315 316 strcpy(names + position, current->name); 317 position += strlen(current->name); 318 names[position++] = 0; 319 ++count; 320 } 321 } 322 323 return count; 324 } 325 326 case PPPoE_QUERY_SERVICES: { 327 // XXX: as all modules are loaded on-demand we must wait for the results 328 329 if (!data || length != sizeof(pppoe_query_request)) 330 return B_ERROR; 331 332 pppoe_query_request *request = (pppoe_query_request*) data; 333 334 pppoe_query query; 335 query.ethernetIfnet = FindPPPoEInterface(request->interfaceName); 336 if (!query.ethernetIfnet) 337 return B_BAD_VALUE; 338 339 query.hostUniq = NewHostUniq(); 340 query.receiver = request->receiver; 341 342 { 343 // MutexLocker tlocker(sLock); 344 TRACE("add query\n"); 345 sQueries->AddItem(&query); 346 } 347 348 snooze(2000000); 349 // wait two seconds for results 350 { 351 // MutexLocker tlocker(sLock); 352 TRACE("remove query\n"); 353 sQueries->RemoveItem(&query); 354 } 355 } break; 356 357 default: 358 return B_ERROR; 359 } 360 361 return B_OK; 362 } 363 364 365 static ppp_module_info pppoe_module = { 366 { 367 PPPoE_MODULE_NAME, 368 0, 369 std_ops 370 }, 371 control, 372 add_to 373 }; 374 375 376 _EXPORT 377 status_t 378 std_ops(int32 op, ...) 379 { 380 switch(op) { 381 case B_MODULE_INIT: 382 if (get_module(NET_STACK_MODULE_NAME, 383 (module_info**)&gStackModule) != B_OK) 384 return B_ERROR; 385 386 if (get_module(NET_DATALINK_MODULE_NAME, 387 (module_info **)&sDatalinkModule) != B_OK) { 388 put_module(NET_STACK_MODULE_NAME); 389 return B_ERROR; 390 } 391 392 if (get_module(NET_BUFFER_MODULE_NAME, 393 (module_info **)&gBufferModule) != B_OK) { 394 put_module(NET_DATALINK_MODULE_NAME); 395 put_module(NET_STACK_MODULE_NAME); 396 return B_ERROR; 397 } 398 399 // set_max_linkhdr(2 + PPPoE_HEADER_SIZE + ETHER_HDR_LEN); 400 // 2 bytes for PPP header 401 sDevices = new TemplateList<PPPoEDevice*>; 402 sQueries = new TemplateList<pppoe_query*>; 403 404 TRACE("PPPoE: Registered PPPoE receiver.\n"); 405 return B_OK; 406 407 case B_MODULE_UNINIT: 408 delete sQueries; 409 delete sDevices; 410 TRACE("PPPoE: Unregistered PPPoE receiver.\n"); 411 put_module(NET_BUFFER_MODULE_NAME); 412 put_module(NET_DATALINK_MODULE_NAME); 413 put_module(NET_STACK_MODULE_NAME); 414 break; 415 416 default: 417 return B_ERROR; 418 } 419 420 return B_OK; 421 } 422 423 424 _EXPORT 425 module_info *modules[] = { 426 (module_info*) &pppoe_module, 427 NULL 428 }; 429