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