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 DownStarted(); 251 // this tells StateMachine that DownEvent() does not mean we lost connection 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=%ld\n", MTU()); 260 DownEvent(); 261 return false; 262 } 263 264 // create destination 265 struct ether_header *ethernetHeader; 266 struct sockaddr destination; 267 memset(&destination, 0, sizeof(destination)); 268 destination.sa_family = AF_UNSPEC; 269 // raw packet with ethernet header 270 ethernetHeader = (struct ether_header*) destination.sa_data; 271 ethernetHeader->type = ETHER_TYPE_PPPOE_DISCOVERY; 272 memcpy(ethernetHeader->destination, fPeer, sizeof(fPeer)); 273 274 // reset connection settings 275 memset(fPeer, 0xFF, sizeof(fPeer)); 276 277 EthernetIfnet()->module->send_data(EthernetIfnet(), packet); 278 DownEvent(); 279 280 return true; 281 } 282 283 284 uint32 285 PPPoEDevice::InputTransferRate() const 286 { 287 return 10000000; 288 } 289 290 291 uint32 292 PPPoEDevice::OutputTransferRate() const 293 { 294 return 10000000; 295 } 296 297 298 uint32 299 PPPoEDevice::CountOutputBytes() const 300 { 301 // TODO: 302 // ?look through ethernet queue for outgoing pppoe packets coming from our device? 303 return 0; 304 } 305 306 307 status_t 308 PPPoEDevice::Send(net_buffer *packet, uint16 protocolNumber) 309 { 310 // Send() is only for PPP packets. PPPoE packets are sent directly to ethernet. 311 312 TRACE("PPPoEDevice: Send()\n"); 313 314 if (!packet) 315 return B_ERROR; 316 else if (InitCheck() != B_OK || protocolNumber != 0) { 317 ERROR("PPPoEDevice::Send(): InitCheck() != B_OK!\n"); 318 gBufferModule->free(packet); 319 return B_ERROR; 320 } 321 322 if (!IsUp()) { 323 ERROR("PPPoEDevice::Send(): no connection!\n"); 324 gBufferModule->free(packet); 325 return PPP_NO_CONNECTION; 326 } 327 328 uint16 length = packet->size; 329 330 // encapsulate packet into pppoe header 331 NetBufferPrepend<pppoe_header> bufferheader(packet); 332 if (bufferheader.Status() != B_OK) 333 return B_ERROR; 334 pppoe_header &header = bufferheader.Data(); 335 header.version = PPPoE_VERSION; 336 header.type = PPPoE_TYPE; 337 header.code = 0x00; 338 header.sessionID = SessionID(); 339 header.length = htons(length); 340 bufferheader.Sync(); 341 342 // create ether header 343 NetBufferPrepend<ether_header> ethernetHeader(packet); 344 if (ethernetHeader.Status() != B_OK) 345 return false; 346 ether_header ðheader = ethernetHeader.Data(); 347 348 memcpy(ethheader.destination, fPeer, ETHER_ADDRESS_LENGTH); 349 memcpy(ethheader.source, fEtherAddr, ETHER_ADDRESS_LENGTH); 350 ethheader.type = htons(ETHER_TYPE_PPPOE); 351 ethernetHeader.Sync(); 352 // raw packet with ethernet header 353 354 if (!packet) 355 ERROR("PPPoEDevice::Send(): packet is NULL!\n"); 356 357 if (EthernetIfnet()->module->send_data(EthernetIfnet(), packet) != B_OK) { 358 ERROR("PPPoEDevice::Send(): EthernetIfnet()->output() failed!\n"); 359 remove_device(this); 360 DownEvent(); 361 // DownEvent() without DownStarted() indicates connection lost 362 return PPP_NO_CONNECTION; 363 } 364 365 return B_OK; 366 } 367 368 369 status_t 370 PPPoEDevice::Receive(net_buffer *packet, uint16 protocolNumber) 371 { 372 TRACE("%s entering %s: protocolNumber:%x\n", __FILE__, __func__, protocolNumber); 373 if (!packet) 374 return B_ERROR; 375 376 if (InitCheck() != B_OK || IsDown()) { 377 dprintf("PPPoED InitCheck fail or IsDown\n"); 378 // gBufferModule->free(packet); 379 dprintf("PPPoEDevice::Receive fail\n"); 380 return B_ERROR; 381 } 382 383 uint8 ethernetSource[6]; 384 struct sockaddr_dl& source = *(struct sockaddr_dl*)packet->source; 385 memcpy(ethernetSource, source.sdl_data, sizeof(fPeer)); 386 387 int32 PPP_Packet_Type = B_NET_FRAME_TYPE(source.sdl_type, 388 ntohs(source.sdl_e_type)); 389 // bufferheader.Remove(); 390 // bufferheader.Sync(); 391 392 if (PPP_Packet_Type == B_NET_FRAME_TYPE_PPPOE) { 393 TRACE("ETHER_TYPE_PPPOE\n"); 394 NetBufferHeaderReader<pppoe_header> bufferheader(packet); 395 if (bufferheader.Status() != B_OK) { 396 TRACE("creat NetBufferHeaderReader fail\n"); 397 return B_ERROR; 398 } 399 pppoe_header &header = bufferheader.Data(); 400 uint16 ppppoe_payload = ntohs(header.length); 401 402 if (!IsUp() || header.version != PPPoE_VERSION || header.type != PPPoE_TYPE 403 || header.code != 0x0 || header.sessionID != SessionID()) { 404 // gBufferModule->free(packet); 405 TRACE("basic pppoe header check fail\n"); 406 return B_ERROR; 407 } 408 409 bufferheader.Remove(); 410 bufferheader.Sync(); 411 412 // trim the packet according to actual pppoe_payload 413 gBufferModule->trim(packet, ppppoe_payload); 414 415 return Interface().ReceiveFromDevice(packet); 416 } 417 418 if (PPP_Packet_Type == B_NET_FRAME_TYPE_PPPOE_DISCOVERY) { 419 dprintf("ETHER_TYPE_PPPOE_DISCOVERY\n"); 420 NetBufferHeaderReader<pppoe_header> bufferheader(packet); 421 if (bufferheader.Status() != B_OK) { 422 dprintf("create NetBufferHeaderReader fail\n"); 423 return B_ERROR; 424 } 425 pppoe_header &header = bufferheader.Data(); 426 427 // we do not need to check HOST_UNIQ tag as this is done in pppoe.cpp 428 if (header.version != PPPoE_VERSION || header.type != PPPoE_TYPE) { 429 // gBufferModule->free(packet); 430 dprintf("PPPoEDevice::Receive fail version type wrong\n"); 431 return B_ERROR; 432 } 433 434 if (IsDown()) { 435 // gBufferModule->free(packet); 436 dprintf("PPPoEDevice::Receive fail PPPoEDev IsDown\n"); 437 return B_ERROR; 438 } 439 440 DiscoveryPacket discovery(packet); 441 switch(discovery.Code()) { 442 case PADO: { 443 dprintf("processing PADO\n"); 444 if (fState != PADI_SENT) { 445 // gBufferModule->free(packet); 446 dprintf("PPPoEDevice::Receive faile not PADI_Sent \n"); 447 return B_OK; 448 } 449 450 bool hasServiceName = false, hasACName = false; 451 pppoe_tag *tag; 452 DiscoveryPacket reply(PADR); 453 for (int32 index = 0; index < discovery.CountTags(); index++) { 454 tag = discovery.TagAt(index); 455 if (!tag) 456 continue; 457 458 switch (tag->type) { 459 case SERVICE_NAME: 460 if (!hasServiceName && (!ServiceName() 461 || ((strlen(ServiceName()) == tag->length) 462 && !memcmp(tag->data, ServiceName(), 463 tag->length)))) { 464 hasServiceName = true; 465 reply.AddTag(tag->type, tag->data, tag->length); 466 } 467 break; 468 469 case AC_NAME: 470 if (!hasACName && (!ACName() 471 || ((strlen(ACName()) == tag->length) 472 && !memcmp(tag->data, ACName(), 473 tag->length)))) { 474 hasACName = true; 475 reply.AddTag(tag->type, tag->data, tag->length); 476 } 477 break; 478 479 case AC_COOKIE: 480 case RELAY_SESSION_ID: 481 reply.AddTag(tag->type, tag->data, tag->length); 482 break; 483 484 case SERVICE_NAME_ERROR: 485 case AC_SYSTEM_ERROR: 486 case GENERIC_ERROR: 487 // gBufferModule->free(packet); 488 dprintf("PPPoEDevice::generic error faile\n"); 489 return B_ERROR; 490 break; 491 492 default: 493 ; 494 } 495 } 496 497 if (!hasServiceName) { 498 // gBufferModule->free(packet); 499 dprintf("PPPoEDevice::Receive faile no svc name\n"); 500 return B_ERROR; 501 } 502 503 dprintf("reply.AddTag\n"); 504 reply.AddTag(HOST_UNIQ, &fHostUniq, sizeof(fHostUniq)); 505 reply.AddTag(END_OF_LIST, NULL, 0); 506 net_buffer *replyPacket = reply.ToNetBuffer(MTU()); 507 if (!replyPacket) { 508 // gBufferModule->free(packet); 509 dprintf("PPPoEDevice::Receive fail no reply pack\n"); 510 return B_ERROR; 511 } 512 513 memcpy(fPeer, ethernetSource, ETHER_ADDRESS_LENGTH); 514 515 // create ether header 516 NetBufferPrepend<ether_header> ethernetHeader(replyPacket); 517 if (ethernetHeader.Status() != B_OK) 518 return false; 519 ether_header &header = ethernetHeader.Data(); 520 521 memcpy(header.destination, fPeer, ETHER_ADDRESS_LENGTH); 522 memcpy(header.source, fEtherAddr, ETHER_ADDRESS_LENGTH); 523 header.type=htons(ETHER_TYPE_PPPOE_DISCOVERY); 524 ethernetHeader.Sync(); 525 // raw packet with ethernet header 526 527 fState = PADR_SENT; 528 529 if (EthernetIfnet()->module->send_data(EthernetIfnet(), replyPacket) != B_OK) { 530 gBufferModule->free(replyPacket); 531 dprintf("PPPoEDevice::Receive fail send PADR\n"); 532 return B_ERROR; 533 } 534 535 fNextTimeout = system_time() + PPPoE_TIMEOUT; 536 } 537 break; 538 case PADS: 539 dprintf("procesing PADS\n"); 540 if (fState != PADR_SENT 541 || memcmp(ethernetSource, fPeer, sizeof(fPeer))) { 542 // gBufferModule->free(packet); 543 dprintf("PPPoEDevice::Receive PADS but no PADR sent\n"); 544 return B_ERROR; 545 } 546 547 fSessionID = header.sessionID; 548 fState = OPENED; 549 fNextTimeout = 0; 550 UpEvent(); 551 break; 552 553 case PADT: 554 dprintf("procesing PADT\n"); 555 if (!IsUp() 556 || memcmp(ethernetSource, fPeer, sizeof(fPeer)) 557 || header.sessionID != SessionID()) { 558 // gBufferModule->free(packet); 559 dprintf("PPPoEDevice::Receive fail not up yet\n"); 560 return B_ERROR; 561 } 562 563 fState = INITIAL; 564 fAttempts = 0; 565 fSessionID = 0; 566 fNextTimeout = 0; 567 remove_device(this); 568 DownEvent(); 569 break; 570 571 default: 572 dprintf("PPPoEDevice::Receive fail unknown pppoed code\n"); 573 // gBufferModule->free(packet); 574 return B_ERROR; 575 } 576 } 577 578 dprintf("PPPoEDevice::Receive PADX fine!\n"); 579 // gBufferModule->free(packet); 580 return B_OK; 581 } 582 583 584 void 585 PPPoEDevice::Pulse() 586 { 587 // We use Pulse() for timeout of connection establishment. 588 if (fNextTimeout == 0 || IsUp() || IsDown()) 589 return; 590 591 // check if timed out 592 if (system_time() >= fNextTimeout) { 593 if (!Up()) 594 UpFailedEvent(); 595 } 596 } 597