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
dump_packet(net_buffer * packet)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
PPPoEDevice(KPPPInterface & interface,driver_parameter * settings)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
InitCheck() const112 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
Up()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
Down()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
InputTransferRate() const287 PPPoEDevice::InputTransferRate() const
288 {
289 return 10000000;
290 }
291
292
293 uint32
OutputTransferRate() const294 PPPoEDevice::OutputTransferRate() const
295 {
296 return 10000000;
297 }
298
299
300 uint32
CountOutputBytes() const301 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
Send(net_buffer * packet,uint16 protocolNumber)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
Receive(net_buffer * packet,uint16 protocolNumber)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
Pulse()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