1 /* 2 * Copyright 2003-2006, Waldemar Kornewald <wkornew@gmx.net> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <cstdlib> 7 8 #include <ByteOrder.h> 9 #include <net/if_dl.h> 10 #include <net_stack.h> 11 12 #include <ethernet.h> 13 #include <ether_driver.h> 14 15 #include "PPPoEDevice.h" 16 #include "DiscoveryPacket.h" 17 18 // from libkernelppp 19 #include <settings_tools.h> 20 21 extern net_stack_module_info *gStackModule; 22 extern net_buffer_module_info *gBufferModule; 23 extern status_t 24 pppoe_input(void *cookie, net_device *_device, net_buffer *packet); 25 26 #if DEBUG 27 static char sDigits[] = "0123456789ABCDEF"; 28 void 29 dump_packet(net_buffer *packet) 30 { 31 if (!packet) 32 return; 33 34 BufferHeaderReader<uint8> bufferheader(packet); 35 if (bufferheader.Status() != B_OK) 36 return; 37 uint8 &buffer = bufferheader.Data(); 38 uint8 *data = &buffer; 39 uint8 buffer[33]; 40 uint8 bufferIndex = 0; 41 42 TRACE("Dumping packet;len=%ld;pkthdr.len=%d\n", packet->m_len, 43 packet->m_flags & M_PKTHDR ? packet->m_pkthdr.len : -1); 44 45 for (uint32 index = 0; index < packet->m_len; index++) { 46 buffer[bufferIndex++] = sDigits[data[index] >> 4]; 47 buffer[bufferIndex++] = sDigits[data[index] & 0x0F]; 48 if (bufferIndex == 32 || index == packet->m_len - 1) { 49 buffer[bufferIndex] = 0; 50 TRACE("%s\n", buffer); 51 bufferIndex = 0; 52 } 53 } 54 } 55 56 57 #endif 58 59 60 PPPoEDevice::PPPoEDevice(KPPPInterface& interface, driver_parameter *settings) 61 : KPPPDevice("PPPoE", PPPoE_HEADER_SIZE + ETHER_HDR_LEN, interface, settings), 62 fEthernetIfnet(NULL), 63 fSessionID(0), 64 fHostUniq(NewHostUniq()), 65 fACName(NULL), 66 fServiceName(NULL), 67 fAttempts(0), 68 fNextTimeout(0), 69 fState(INITIAL) 70 { 71 #if DEBUG 72 TRACE("PPPoEDevice: Constructor\n"); 73 if (!settings || !settings->parameters) 74 TRACE("PPPoEDevice::ctor: No settings!\n"); 75 #endif 76 77 interface.SetPFCOptions(PPP_ALLOW_PFC); 78 // we do not want to fail just because the other side requests PFC 79 80 memset(fPeer, 0xFF, sizeof(fPeer)); 81 82 SetMTU(1494); 83 // MTU size does not contain PPP header 84 85 if (!settings) 86 dprintf("%s::%s: settings is NULL\n", __FILE__, __func__); 87 88 // find ethernet device 89 finterfaceName = get_parameter_value(PPPoE_INTERFACE_KEY, settings); 90 TRACE("%s::%s: finterfaceName is %s\n", __FILE__, __func__, 91 finterfaceName ? finterfaceName : "NULL"); 92 93 fACName = get_parameter_value(PPPoE_AC_NAME_KEY, settings); 94 TRACE("fACName is %s\n", fACName ? fACName : "NULL"); 95 96 fServiceName = get_parameter_value(PPPoE_SERVICE_NAME_KEY, settings); 97 TRACE("fServiceName is %s\n", fServiceName ? fServiceName : "NULL"); 98 99 // fEthernetIfnet = FindPPPoEInterface(interfaceName); 100 101 #if DEBUG 102 if (!fEthernetIfnet) 103 TRACE("PPPoEDevice::ctor: could not find ethernet interface\n"); 104 else 105 TRACE("%s::%s: Find Ethernet device", __FILE__, __func__); 106 #endif 107 } 108 109 110 status_t 111 PPPoEDevice::InitCheck() const 112 { 113 if (KPPPDevice::InitCheck() != B_OK) 114 dprintf("%s::%s: KPPPDevice::InitCheck() has error\n", __FILE__, __func__); 115 116 return KPPPDevice::InitCheck() == B_OK ? B_OK : B_ERROR; 117 } 118 119 120 bool 121 PPPoEDevice::Up() 122 { 123 TRACE("PPPoEDevice: Up()\n"); 124 125 if (InitCheck() != B_OK) 126 return false; 127 128 if (IsUp()) 129 return true; 130 131 fEthernetIfnet = FindPPPoEInterface(finterfaceName); 132 133 if (fEthernetIfnet == NULL) { 134 dprintf("%s::%s: fEthernetIfnet %s not found\n", __FILE__, __func__, finterfaceName); 135 return false; 136 } 137 138 memcpy(fEtherAddr, fEthernetIfnet->address.data, ETHER_ADDRESS_LENGTH); 139 dprintf("ppp's corresponding addr is %02x:%02x:%02x:%02x:%02x:%02x\n", 140 fEtherAddr[0], fEtherAddr[1], fEtherAddr[2], fEtherAddr[3], 141 fEtherAddr[4], fEtherAddr[5]); 142 143 if (fEthernetIfnet->module == NULL) { 144 dprintf("%s::%s: fEthernetIfnet->module not found\n", __FILE__, 145 __func__); 146 return false; 147 } 148 149 add_device(this); 150 151 fState = INITIAL; 152 // reset state 153 154 if (fAttempts > PPPoE_MAX_ATTEMPTS) { 155 fAttempts = 0; 156 return false; 157 } 158 159 ++fAttempts; 160 // reset connection settings 161 memset(fPeer, 0xFF, sizeof(fPeer)); 162 163 // create PADI 164 DiscoveryPacket discovery(PADI); 165 if (ServiceName()) 166 discovery.AddTag(SERVICE_NAME, ServiceName(), strlen(ServiceName())); 167 else 168 discovery.AddTag(SERVICE_NAME, NULL, 0); 169 discovery.AddTag(HOST_UNIQ, &fHostUniq, sizeof(fHostUniq)); 170 discovery.AddTag(END_OF_LIST, NULL, 0); 171 172 // set up PPP header 173 net_buffer *packet = discovery.ToNetBuffer(MTU()); 174 if (!packet) 175 return false; 176 177 // create ether header 178 NetBufferPrepend<ether_header> ethernetHeader(packet); 179 if (ethernetHeader.Status() != B_OK) 180 return false; 181 ether_header &header = ethernetHeader.Data(); 182 183 memset(header.destination, 0xff, ETHER_ADDRESS_LENGTH); 184 memcpy(header.source, fEtherAddr, ETHER_ADDRESS_LENGTH); 185 header.type = htons(ETHER_TYPE_PPPOE_DISCOVERY); 186 ethernetHeader.Sync(); 187 // raw packet with ethernet header 188 189 // check if we are allowed to go up now (user intervention might disallow that) 190 if (fAttempts > 0 && !UpStarted()) { 191 fAttempts = 0; 192 remove_device(this); 193 DownEvent(); 194 return true; 195 // there was no error 196 } 197 198 fState = PADI_SENT; 199 // needed before sending, otherwise we might not get all packets 200 201 status_t status = gStackModule->register_device_handler(fEthernetIfnet, 202 B_NET_FRAME_TYPE_PPPOE_DISCOVERY, &pppoe_input, NULL); 203 if (status != B_OK) 204 return false; 205 206 status = gStackModule->register_device_handler(fEthernetIfnet, 207 B_NET_FRAME_TYPE_PPPOE, &pppoe_input, NULL); 208 if (status != B_OK) 209 return false; 210 211 if (EthernetIfnet()->module->send_data(EthernetIfnet(), packet) != B_OK) { 212 fState = INITIAL; 213 fAttempts = 0; 214 ERROR("PPPoEDevice::Up(): EthernetIfnet()->output() failed!\n"); 215 return false; 216 } 217 218 dprintf("PPPoEDevice::Up(): EthernetIfnet()->output() success!\n"); 219 fNextTimeout = system_time() + PPPoE_TIMEOUT; 220 221 return true; 222 } 223 224 225 bool 226 PPPoEDevice::Down() 227 { 228 TRACE("PPPoEDevice: Down()\n"); 229 230 gStackModule->unregister_device_handler(fEthernetIfnet, 231 B_NET_FRAME_TYPE_PPPOE_DISCOVERY); 232 gStackModule->unregister_device_handler(fEthernetIfnet, 233 B_NET_FRAME_TYPE_PPPOE); 234 235 remove_device(this); 236 237 if (InitCheck() != B_OK) 238 return false; 239 240 fState = INITIAL; 241 fAttempts = 0; 242 fNextTimeout = 0; 243 // disable timeouts 244 245 if (!IsUp()) { 246 DownEvent(); 247 return true; 248 } 249 250 // this tells StateMachine that DownEvent() does not mean we lost connection 251 DownStarted(); 252 253 // create PADT 254 DiscoveryPacket discovery(PADT, SessionID()); 255 discovery.AddTag(END_OF_LIST, NULL, 0); 256 257 net_buffer *packet = discovery.ToNetBuffer(MTU()); 258 if (!packet) { 259 ERROR("PPPoEDevice::Down(): ToNetBuffer() failed; MTU=%" B_PRIu32 "\n", 260 MTU()); 261 DownEvent(); 262 return false; 263 } 264 265 // create destination 266 struct ether_header *ethernetHeader; 267 struct sockaddr destination; 268 memset(&destination, 0, sizeof(destination)); 269 destination.sa_family = AF_UNSPEC; 270 // raw packet with ethernet header 271 ethernetHeader = (struct ether_header*) destination.sa_data; 272 ethernetHeader->type = ETHER_TYPE_PPPOE_DISCOVERY; 273 memcpy(ethernetHeader->destination, fPeer, sizeof(fPeer)); 274 275 // reset connection settings 276 memset(fPeer, 0xFF, sizeof(fPeer)); 277 278 EthernetIfnet()->module->send_data(EthernetIfnet(), packet); 279 DownEvent(); 280 281 return true; 282 } 283 284 285 uint32 286 PPPoEDevice::InputTransferRate() const 287 { 288 return 10000000; 289 } 290 291 292 uint32 293 PPPoEDevice::OutputTransferRate() const 294 { 295 return 10000000; 296 } 297 298 299 uint32 300 PPPoEDevice::CountOutputBytes() const 301 { 302 // TODO: 303 // ?look through ethernet queue for outgoing pppoe packets coming from our device? 304 return 0; 305 } 306 307 308 status_t 309 PPPoEDevice::Send(net_buffer *packet, uint16 protocolNumber) 310 { 311 // Send() is only for PPP packets. PPPoE packets are sent directly to ethernet. 312 313 TRACE("PPPoEDevice: Send()\n"); 314 315 if (!packet) 316 return B_ERROR; 317 else if (InitCheck() != B_OK || protocolNumber != 0) { 318 ERROR("PPPoEDevice::Send(): InitCheck() != B_OK!\n"); 319 gBufferModule->free(packet); 320 return B_ERROR; 321 } 322 323 if (!IsUp()) { 324 ERROR("PPPoEDevice::Send(): no connection!\n"); 325 gBufferModule->free(packet); 326 return PPP_NO_CONNECTION; 327 } 328 329 uint16 length = packet->size; 330 331 // encapsulate packet into pppoe header 332 NetBufferPrepend<pppoe_header> bufferheader(packet); 333 if (bufferheader.Status() != B_OK) 334 return B_ERROR; 335 pppoe_header &header = bufferheader.Data(); 336 header.version = PPPoE_VERSION; 337 header.type = PPPoE_TYPE; 338 header.code = 0x00; 339 header.sessionID = SessionID(); 340 header.length = htons(length); 341 bufferheader.Sync(); 342 343 // create ether header 344 NetBufferPrepend<ether_header> ethernetHeader(packet); 345 if (ethernetHeader.Status() != B_OK) 346 return false; 347 ether_header ðheader = ethernetHeader.Data(); 348 349 memcpy(ethheader.destination, fPeer, ETHER_ADDRESS_LENGTH); 350 memcpy(ethheader.source, fEtherAddr, ETHER_ADDRESS_LENGTH); 351 ethheader.type = htons(ETHER_TYPE_PPPOE); 352 ethernetHeader.Sync(); 353 // raw packet with ethernet header 354 355 if (!packet) 356 ERROR("PPPoEDevice::Send(): packet is NULL!\n"); 357 358 if (EthernetIfnet()->module->send_data(EthernetIfnet(), packet) != B_OK) { 359 ERROR("PPPoEDevice::Send(): EthernetIfnet()->output() failed!\n"); 360 remove_device(this); 361 DownEvent(); 362 // DownEvent() without DownStarted() indicates connection lost 363 return PPP_NO_CONNECTION; 364 } 365 366 return B_OK; 367 } 368 369 370 status_t 371 PPPoEDevice::Receive(net_buffer *packet, uint16 protocolNumber) 372 { 373 TRACE("%s entering %s: protocolNumber:%x\n", __FILE__, __func__, protocolNumber); 374 if (!packet) 375 return B_ERROR; 376 377 if (InitCheck() != B_OK || IsDown()) { 378 dprintf("PPPoED InitCheck fail or IsDown\n"); 379 // gBufferModule->free(packet); 380 dprintf("PPPoEDevice::Receive fail\n"); 381 return B_ERROR; 382 } 383 384 uint8 ethernetSource[6]; 385 struct sockaddr_dl& source = *(struct sockaddr_dl*)packet->source; 386 memcpy(ethernetSource, source.sdl_data, sizeof(fPeer)); 387 388 int32 PPP_Packet_Type = B_NET_FRAME_TYPE(source.sdl_type, 389 ntohs(source.sdl_e_type)); 390 // bufferheader.Remove(); 391 // bufferheader.Sync(); 392 393 if (PPP_Packet_Type == B_NET_FRAME_TYPE_PPPOE) { 394 TRACE("ETHER_TYPE_PPPOE\n"); 395 NetBufferHeaderReader<pppoe_header> bufferheader(packet); 396 if (bufferheader.Status() != B_OK) { 397 TRACE("creat NetBufferHeaderReader fail\n"); 398 return B_ERROR; 399 } 400 pppoe_header &header = bufferheader.Data(); 401 uint16 ppppoe_payload = ntohs(header.length); 402 403 if (!IsUp() || header.version != PPPoE_VERSION || header.type != PPPoE_TYPE 404 || header.code != 0x0 || header.sessionID != SessionID()) { 405 // gBufferModule->free(packet); 406 TRACE("basic pppoe header check fail\n"); 407 return B_ERROR; 408 } 409 410 bufferheader.Remove(); 411 bufferheader.Sync(); 412 413 // trim the packet according to actual pppoe_payload 414 gBufferModule->trim(packet, ppppoe_payload); 415 416 return Interface().ReceiveFromDevice(packet); 417 } 418 419 if (PPP_Packet_Type == B_NET_FRAME_TYPE_PPPOE_DISCOVERY) { 420 dprintf("ETHER_TYPE_PPPOE_DISCOVERY\n"); 421 NetBufferHeaderReader<pppoe_header> bufferheader(packet); 422 if (bufferheader.Status() != B_OK) { 423 dprintf("create NetBufferHeaderReader fail\n"); 424 return B_ERROR; 425 } 426 pppoe_header &header = bufferheader.Data(); 427 428 // we do not need to check HOST_UNIQ tag as this is done in pppoe.cpp 429 if (header.version != PPPoE_VERSION || header.type != PPPoE_TYPE) { 430 // gBufferModule->free(packet); 431 dprintf("PPPoEDevice::Receive fail version type wrong\n"); 432 return B_ERROR; 433 } 434 435 if (IsDown()) { 436 // gBufferModule->free(packet); 437 dprintf("PPPoEDevice::Receive fail PPPoEDev IsDown\n"); 438 return B_ERROR; 439 } 440 441 DiscoveryPacket discovery(packet); 442 switch(discovery.Code()) { 443 case PADO: { 444 dprintf("processing PADO\n"); 445 if (fState != PADI_SENT) { 446 // gBufferModule->free(packet); 447 dprintf("PPPoEDevice::Receive faile not PADI_Sent \n"); 448 return B_OK; 449 } 450 451 bool hasServiceName = false, hasACName = false; 452 pppoe_tag *tag; 453 DiscoveryPacket reply(PADR); 454 for (int32 index = 0; index < discovery.CountTags(); index++) { 455 tag = discovery.TagAt(index); 456 if (!tag) 457 continue; 458 459 switch (tag->type) { 460 case SERVICE_NAME: 461 if (!hasServiceName && (!ServiceName() 462 || ((strlen(ServiceName()) == tag->length) 463 && !memcmp(tag->data, ServiceName(), 464 tag->length)))) { 465 hasServiceName = true; 466 reply.AddTag(tag->type, tag->data, tag->length); 467 } 468 break; 469 470 case AC_NAME: 471 if (!hasACName && (!ACName() 472 || ((strlen(ACName()) == tag->length) 473 && !memcmp(tag->data, ACName(), 474 tag->length)))) { 475 hasACName = true; 476 reply.AddTag(tag->type, tag->data, tag->length); 477 } 478 break; 479 480 case AC_COOKIE: 481 case RELAY_SESSION_ID: 482 reply.AddTag(tag->type, tag->data, tag->length); 483 break; 484 485 case SERVICE_NAME_ERROR: 486 case AC_SYSTEM_ERROR: 487 case GENERIC_ERROR: 488 // gBufferModule->free(packet); 489 dprintf("PPPoEDevice::generic error faile\n"); 490 return B_ERROR; 491 break; 492 493 default: 494 ; 495 } 496 } 497 498 if (!hasServiceName) { 499 // gBufferModule->free(packet); 500 dprintf("PPPoEDevice::Receive faile no svc name\n"); 501 return B_ERROR; 502 } 503 504 dprintf("reply.AddTag\n"); 505 reply.AddTag(HOST_UNIQ, &fHostUniq, sizeof(fHostUniq)); 506 reply.AddTag(END_OF_LIST, NULL, 0); 507 net_buffer *replyPacket = reply.ToNetBuffer(MTU()); 508 if (!replyPacket) { 509 // gBufferModule->free(packet); 510 dprintf("PPPoEDevice::Receive fail no reply pack\n"); 511 return B_ERROR; 512 } 513 514 memcpy(fPeer, ethernetSource, ETHER_ADDRESS_LENGTH); 515 516 // create ether header 517 NetBufferPrepend<ether_header> ethernetHeader(replyPacket); 518 if (ethernetHeader.Status() != B_OK) 519 return false; 520 ether_header &header = ethernetHeader.Data(); 521 522 memcpy(header.destination, fPeer, ETHER_ADDRESS_LENGTH); 523 memcpy(header.source, fEtherAddr, ETHER_ADDRESS_LENGTH); 524 header.type=htons(ETHER_TYPE_PPPOE_DISCOVERY); 525 ethernetHeader.Sync(); 526 // raw packet with ethernet header 527 528 fState = PADR_SENT; 529 530 if (EthernetIfnet()->module->send_data(EthernetIfnet(), replyPacket) != B_OK) { 531 gBufferModule->free(replyPacket); 532 dprintf("PPPoEDevice::Receive fail send PADR\n"); 533 return B_ERROR; 534 } 535 536 fNextTimeout = system_time() + PPPoE_TIMEOUT; 537 } 538 break; 539 case PADS: 540 dprintf("procesing PADS\n"); 541 if (fState != PADR_SENT 542 || memcmp(ethernetSource, fPeer, sizeof(fPeer))) { 543 // gBufferModule->free(packet); 544 dprintf("PPPoEDevice::Receive PADS but no PADR sent\n"); 545 return B_ERROR; 546 } 547 548 fSessionID = header.sessionID; 549 fState = OPENED; 550 fNextTimeout = 0; 551 UpEvent(); 552 break; 553 554 case PADT: 555 dprintf("procesing PADT\n"); 556 if (!IsUp() 557 || memcmp(ethernetSource, fPeer, sizeof(fPeer)) 558 || header.sessionID != SessionID()) { 559 // gBufferModule->free(packet); 560 dprintf("PPPoEDevice::Receive fail not up yet\n"); 561 return B_ERROR; 562 } 563 564 fState = INITIAL; 565 fAttempts = 0; 566 fSessionID = 0; 567 fNextTimeout = 0; 568 remove_device(this); 569 DownEvent(); 570 break; 571 572 default: 573 dprintf("PPPoEDevice::Receive fail unknown pppoed code\n"); 574 // gBufferModule->free(packet); 575 return B_ERROR; 576 } 577 } 578 579 dprintf("PPPoEDevice::Receive PADX fine!\n"); 580 // gBufferModule->free(packet); 581 return B_OK; 582 } 583 584 585 void 586 PPPoEDevice::Pulse() 587 { 588 // We use Pulse() for timeout of connection establishment. 589 if (fNextTimeout == 0 || IsUp() || IsDown()) 590 return; 591 592 // check if timed out 593 if (system_time() >= fNextTimeout) { 594 if (!Up()) 595 UpFailedEvent(); 596 } 597 } 598