xref: /haiku/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPInterface.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
1 /*
2  * Copyright 2003-2007, Waldemar Kornewald <wkornew@gmx.net>
3  * Distributed under the terms of the MIT License.
4  */
5 
6 /*!	\class KPPPInterface
7 	\brief The kernel representation of a PPP interface.
8 
9 	This class is never created by the programmer directly. Instead, the PPP manager
10 	kernel module should be used. \n
11 	KPPPInterface handles all interface-specific commands from userspace and it
12 	passes packets to their receiver or sends them to the device. Additionally,
13 	it contains the KPPPLCP object with represents the LCP protocol and the
14 	KPPPStateMachine object which represents the state machine. \n
15 	All PPP modules are loaded from here. \n
16 	Protocols and encapsulators should be added to this class. LCP-specific extensions
17 	belong to the KPPPLCP object. \n
18 	Multilink support is distributed between KPPPInterface and KPPPStateMachine.
19 */
20 
21 // cstdio must be included before KPPPModule.h/KPPPManager.h because
22 // dprintf is defined twice with different return values, once with
23 // void (KernelExport.h) and once with int (stdio.h).
24 #include <cstdio>
25 #include <cstring>
26 #include <core_funcs.h>
27 
28 // now our headers...
29 #include <KPPPInterface.h>
30 
31 // our other classes
32 #include <PPPControl.h>
33 #include <KPPPDevice.h>
34 #include <KPPPLCPExtension.h>
35 #include <KPPPOptionHandler.h>
36 #include <KPPPModule.h>
37 #include <KPPPManager.h>
38 #include <KPPPUtils.h>
39 
40 // general helper classes not only belonging to us
41 #include <LockerHelper.h>
42 
43 // tools only for us :)
44 #include "settings_tools.h"
45 
46 // internal modules
47 #include "_KPPPMRUHandler.h"
48 #include "_KPPPAuthenticationHandler.h"
49 #include "_KPPPPFCHandler.h"
50 
51 
52 // TODO:
53 // - implement timers with support for setting next event instead of receiving timer
54 //    events periodically
55 // - add missing settings support (ConnectRetryDelay, etc.)
56 
57 
58 //!	Private structure needed for reconnecting.
59 typedef struct reconnect_info {
60 	KPPPInterface *interface;
61 	thread_id *thread;
62 	uint32 delay;
63 } reconnect_info;
64 
65 status_t reconnect_thread(void *data);
66 
67 // other functions
68 status_t interface_deleter_thread(void *data);
69 
70 
71 /*!	\brief Creates a new interface.
72 
73 	\param name Name of the PPP interface description file.
74 	\param entry The PPP manager passes an internal structure to the constructor.
75 	\param ID The interface's ID.
76 	\param settings (Optional): If no name is given you must pass the settings here.
77 	\param parent (Optional): Interface's parent (only used for multilink interfaces).
78 */
79 KPPPInterface::KPPPInterface(const char *name, ppp_interface_entry *entry,
80 	ppp_interface_id ID, const driver_settings *settings, KPPPInterface *parent)
81 	:
82 	KPPPLayer(name, PPP_INTERFACE_LEVEL, 2),
83 	fID(ID),
84 	fSettings(NULL),
85 	fIfnet(NULL),
86 	fReconnectThread(-1),
87 	fConnectAttempt(1),
88 	fConnectRetriesLimit(0),
89 	fManager(NULL),
90 	fConnectedSince(0),
91 	fIdleSince(0),
92 	fMRU(1500),
93 	fInterfaceMTU(1498),
94 	fHeaderLength(2),
95 	fParent(NULL),
96 	fIsMultilink(false),
97 	fAutoReconnect(false),
98 	fConnectOnDemand(false),
99 	fAskBeforeConnecting(false),
100 	fMode(PPP_CLIENT_MODE),
101 	fLocalPFCState(PPP_PFC_DISABLED),
102 	fPeerPFCState(PPP_PFC_DISABLED),
103 	fPFCOptions(0),
104 	fDevice(NULL),
105 	fFirstProtocol(NULL),
106 	fStateMachine(*this),
107 	fLCP(*this),
108 	fReportManager(StateMachine().fLock),
109 	fLock(StateMachine().fLock),
110 	fDeleteCounter(0)
111 {
112 	entry->interface = this;
113 
114 	if (name) {
115 		// load settings from description file
116 		char path[B_PATH_NAME_LENGTH];
117 		sprintf(path, "ptpnet/%s", name);
118 			// XXX: TODO: change base path to "/etc/ptpnet"
119 
120 		void *handle = load_driver_settings(path);
121 		if (!handle) {
122 			fInitStatus = B_ERROR;
123 			return;
124 		}
125 
126 		fSettings = dup_driver_settings(get_driver_settings(handle));
127 		unload_driver_settings(handle);
128 	} else
129 		fSettings = dup_driver_settings(settings);
130 			// use the given settings
131 
132 	if (!fSettings) {
133 		fInitStatus = B_ERROR;
134 		return;
135 	}
136 
137 	// add internal modules
138 	// LCP
139 	if (!AddProtocol(&LCP())) {
140 		fInitStatus = B_ERROR;
141 		return;
142 	}
143 	// MRU
144 	_KPPPMRUHandler *mruHandler =
145 		new _KPPPMRUHandler(*this);
146 	if (!LCP().AddOptionHandler(mruHandler) || mruHandler->InitCheck() != B_OK) {
147 		ERROR("KPPPInterface: Could not add MRU handler!\n");
148 		delete mruHandler;
149 	}
150 	// authentication
151 	_KPPPAuthenticationHandler *authenticationHandler =
152 		new _KPPPAuthenticationHandler(*this);
153 	if (!LCP().AddOptionHandler(authenticationHandler)
154 			|| authenticationHandler->InitCheck() != B_OK) {
155 		ERROR("KPPPInterface: Could not add authentication handler!\n");
156 		delete authenticationHandler;
157 	}
158 	// PFC
159 	_KPPPPFCHandler *pfcHandler =
160 		new _KPPPPFCHandler(fLocalPFCState, fPeerPFCState, *this);
161 	if (!LCP().AddOptionHandler(pfcHandler) || pfcHandler->InitCheck() != B_OK) {
162 		ERROR("KPPPInterface: Could not add PFC handler!\n");
163 		delete pfcHandler;
164 	}
165 
166 	// set up connect delays
167 	fConnectRetryDelay = 3000;
168 		// 3s delay between each new attempt to reconnect
169 	fReconnectDelay = 1000;
170 		// 1s delay between lost connection and reconnect
171 
172 	if (get_module(PPP_INTERFACE_MODULE_NAME, (module_info**) &fManager) != B_OK)
173 		ERROR("KPPPInterface: Manager module not found!\n");
174 
175 	// are we a multilink subinterface?
176 	if (parent && parent->IsMultilink()) {
177 		fParent = parent;
178 		fParent->AddChild(this);
179 		fIsMultilink = true;
180 	}
181 
182 	RegisterInterface();
183 
184 	if (!fSettings) {
185 		fInitStatus = B_ERROR;
186 		return;
187 	}
188 
189 	const char *value;
190 
191 	// get login
192 	value = get_settings_value(PPP_USERNAME_KEY, fSettings);
193 	fUsername = value ? strdup(value) : strdup("");
194 	value = get_settings_value(PPP_PASSWORD_KEY, fSettings);
195 	fPassword = value ? strdup(value) : strdup("");
196 
197 	// get DisonnectAfterIdleSince settings
198 	value = get_settings_value(PPP_DISONNECT_AFTER_IDLE_SINCE_KEY, fSettings);
199 	if (!value)
200 		fDisconnectAfterIdleSince = 0;
201 	else
202 		fDisconnectAfterIdleSince = atoi(value) * 1000;
203 
204 	if (fDisconnectAfterIdleSince < 0)
205 		fDisconnectAfterIdleSince = 0;
206 
207 	// get mode settings
208 	value = get_settings_value(PPP_MODE_KEY, fSettings);
209 	if (value && !strcasecmp(value, PPP_SERVER_MODE_VALUE))
210 		fMode = PPP_SERVER_MODE;
211 	else
212 		fMode = PPP_CLIENT_MODE;
213 		// we are a client by default
214 
215 	SetAutoReconnect(
216 		get_boolean_value(
217 		get_settings_value(PPP_AUTO_RECONNECT_KEY, fSettings),
218 		false)
219 		);
220 		// auto reconnect is disabled by default
221 
222 	fAskBeforeConnecting = get_boolean_value(
223 		get_settings_value(PPP_ASK_BEFORE_CONNECTING_KEY, fSettings), false);
224 
225 	// load all protocols and the device
226 	if (!LoadModules(fSettings, 0, fSettings->parameter_count)) {
227 		ERROR("KPPPInterface: Error loading modules!\n");
228 		fInitStatus = B_ERROR;
229 	}
230 }
231 
232 
233 //!	Destructor: Disconnects and marks interface for deletion.
234 KPPPInterface::~KPPPInterface()
235 {
236 	TRACE("KPPPInterface: Destructor\n");
237 
238 	// tell protocols to uninit (remove routes, etc.)
239 	KPPPProtocol *protocol = FirstProtocol();
240 	for (; protocol; protocol = protocol->NextProtocol())
241 		protocol->Uninit();
242 
243 	// make sure we are not accessible by any thread before we continue
244 	UnregisterInterface();
245 
246 	if (fManager)
247 		fManager->RemoveInterface(ID());
248 
249 	// Call Down() until we get a lock on an interface that is down.
250 	// This lock is not released until we are actually deleted.
251 	while (true) {
252 		Down();
253 		fLock.Lock();
254 		if (State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE)
255 			break;
256 		fLock.Unlock();
257 	}
258 
259 	Report(PPP_DESTRUCTION_REPORT, 0, &fID, sizeof(ppp_interface_id));
260 		// tell all listeners that we are being destroyed
261 
262 	int32 tmp;
263 	send_data_with_timeout(fReconnectThread, 0, NULL, 0, 200);
264 		// tell thread that we are being destroyed (200ms timeout)
265 	wait_for_thread(fReconnectThread, &tmp);
266 
267 	while (CountChildren())
268 		delete ChildAt(0);
269 
270 	delete Device();
271 
272 	while (FirstProtocol()) {
273 		if (FirstProtocol() == &LCP())
274 			fFirstProtocol = fFirstProtocol->NextProtocol();
275 		else
276 			delete FirstProtocol();
277 				// destructor removes protocol from list
278 	}
279 
280 	for (int32 index = 0; index < fModules.CountItems(); index++) {
281 		put_module(fModules.ItemAt(index));
282 		delete[] fModules.ItemAt(index);
283 	}
284 
285 	free_driver_settings(fSettings);
286 
287 	if (Parent())
288 		Parent()->RemoveChild(this);
289 
290 	if (fManager)
291 		put_module(PPP_INTERFACE_MODULE_NAME);
292 }
293 
294 
295 //!	Marks interface for deletion.
296 void
297 KPPPInterface::Delete()
298 {
299 	LockerHelper locker(fLock);
300 
301 	if (fDeleteCounter > 0)
302 		return;
303 			// only one thread should delete us!
304 
305 	fDeleteCounter = 1;
306 
307 	fManager->DeleteInterface(ID());
308 		// This will mark us for deletion.
309 		// Any subsequent calls to delete_interface() will do nothing.
310 }
311 
312 
313 //!	Returns if interface was initialized correctly.
314 status_t
315 KPPPInterface::InitCheck() const
316 {
317 	if (fInitStatus != B_OK)
318 		return fInitStatus;
319 
320 	if (!fSettings || !fManager)
321 		return B_ERROR;
322 
323 	// sub-interfaces should have a device
324 	if (IsMultilink()) {
325 		if (Parent() && !fDevice)
326 			return B_ERROR;
327 	} else if (!fDevice)
328 		return B_ERROR;
329 
330 	return B_OK;
331 }
332 
333 
334 //!	The username used for authentication.
335 const char*
336 KPPPInterface::Username() const
337 {
338 	// this data is not available before we authenticate
339 	if (Phase() < PPP_AUTHENTICATION_PHASE)
340 		return NULL;
341 
342 	return fUsername;
343 }
344 
345 
346 //!	The password used for authentication.
347 const char*
348 KPPPInterface::Password() const
349 {
350 	// this data is not available before we authenticate
351 	if (Phase() < PPP_AUTHENTICATION_PHASE)
352 		return NULL;
353 
354 	return fPassword;
355 }
356 
357 
358 //!	Sets interface MRU.
359 bool
360 KPPPInterface::SetMRU(uint32 MRU)
361 {
362 	TRACE("KPPPInterface: SetMRU(%ld)\n", MRU);
363 
364 	if (Device() && MRU > Device()->MTU() - 2)
365 		return false;
366 
367 	LockerHelper locker(fLock);
368 
369 	fMRU = MRU;
370 
371 	CalculateInterfaceMTU();
372 
373 	return true;
374 }
375 
376 
377 //!	Returns number of bytes spent for protocol overhead. Includes device overhead.
378 uint32
379 KPPPInterface::PacketOverhead() const
380 {
381 	uint32 overhead = fHeaderLength + 2;
382 
383 	if (Device())
384 		overhead += Device()->Overhead();
385 
386 	return overhead;
387 }
388 
389 
390 /*!	\brief Allows accessing additional functions.
391 
392 	This is normally called by userland apps to get information about the interface.
393 
394 	\param op The op value (see ppp_control_ops enum).
395 	\param data (Optional): Additional data may be needed for this op.
396 	\param length Length of data.
397 
398 	\return
399 		- \c B_OK: \c Control() was successful.
400 		- \c B_ERROR: Either \a length is too small or data is NULL.
401 		- \c B_NOT_ALLOWED: Operation not allowed (at this point in time).
402 		- \c B_BAD_INDEX: Wrong index (e.g.: when accessing interface submodules).
403 		- \c B_BAD_VALUE: Unknown op.
404 		- Return value of submodule (when controlling one).
405 */
406 status_t
407 KPPPInterface::Control(uint32 op, void *data, size_t length)
408 {
409 	switch (op) {
410 		case PPPC_GET_INTERFACE_INFO:
411 		{
412 			if (length < sizeof(ppp_interface_info_t) || !data)
413 				return B_ERROR;
414 
415 			ppp_interface_info *info = (ppp_interface_info*) data;
416 			memset(info, 0, sizeof(ppp_interface_info_t));
417 			if (Name())
418 				strncpy(info->name, Name(), PPP_HANDLER_NAME_LENGTH_LIMIT);
419 			if (Ifnet())
420 				info->if_unit = Ifnet()->if_unit;
421 			else
422 				info->if_unit = -1;
423 			info->mode = Mode();
424 			info->state = State();
425 			info->phase = Phase();
426 			info->localAuthenticationStatus =
427 				StateMachine().LocalAuthenticationStatus();
428 			info->peerAuthenticationStatus =
429 				StateMachine().PeerAuthenticationStatus();
430 			info->localPFCState = LocalPFCState();
431 			info->peerPFCState = PeerPFCState();
432 			info->pfcOptions = PFCOptions();
433 			info->protocolsCount = CountProtocols();
434 			info->optionHandlersCount = LCP().CountOptionHandlers();
435 			info->LCPExtensionsCount = 0;
436 			info->childrenCount = CountChildren();
437 			info->MRU = MRU();
438 			info->interfaceMTU = InterfaceMTU();
439 			info->connectAttempt = fConnectAttempt;
440 			info->connectRetriesLimit = fConnectRetriesLimit;
441 			info->connectRetryDelay = ConnectRetryDelay();
442 			info->reconnectDelay = ReconnectDelay();
443 			info->connectedSince = ConnectedSince();
444 			info->idleSince = IdleSince();
445 			info->disconnectAfterIdleSince = DisconnectAfterIdleSince();
446 			info->doesConnectOnDemand = DoesConnectOnDemand();
447 			info->doesAutoReconnect = DoesAutoReconnect();
448 			info->hasDevice = Device();
449 			info->isMultilink = IsMultilink();
450 			info->hasParent = Parent();
451 			break;
452 		}
453 
454 		case PPPC_SET_USERNAME:
455 		{
456 			if (!data)
457 				return B_ERROR;
458 
459 			LockerHelper locker(fLock);
460 			// login information can only be changed before we authenticate
461 			if (Phase() >= PPP_AUTHENTICATION_PHASE)
462 				return B_NOT_ALLOWED;
463 
464 			free(fUsername);
465 			fUsername = data ? strdup((const char*) data) : strdup("");
466 			break;
467 		}
468 
469 		case PPPC_SET_PASSWORD:
470 		{
471 			if (!data)
472 				return B_ERROR;
473 
474 			LockerHelper locker(fLock);
475 			// login information can only be changed before we authenticate
476 			if (Phase() >= PPP_AUTHENTICATION_PHASE)
477 				return B_NOT_ALLOWED;
478 
479 			free(fPassword);
480 			fPassword = data ? strdup((const char*) data) : strdup("");
481 			break;
482 		}
483 
484 		case PPPC_SET_ASK_BEFORE_CONNECTING:
485 			if (length < sizeof(uint32) || !data)
486 				return B_ERROR;
487 
488 			SetAskBeforeConnecting(*((uint32*)data));
489 			break;
490 
491 		case PPPC_SET_MRU:
492 			if (length < sizeof(uint32) || !data)
493 				return B_ERROR;
494 
495 			SetMRU(*((uint32*)data));
496 			break;
497 
498 		case PPPC_SET_CONNECT_ON_DEMAND:
499 			if (length < sizeof(uint32) || !data)
500 				return B_ERROR;
501 
502 			SetConnectOnDemand(*((uint32*)data));
503 			break;
504 
505 		case PPPC_SET_AUTO_RECONNECT:
506 			if (length < sizeof(uint32) || !data)
507 				return B_ERROR;
508 
509 			SetAutoReconnect(*((uint32*)data));
510 			break;
511 
512 		case PPPC_HAS_INTERFACE_SETTINGS:
513 			if (length < sizeof(driver_settings) || !data)
514 				return B_ERROR;
515 
516 			if (equal_interface_settings(Settings(), (driver_settings*) data))
517 				return B_OK;
518 			else
519 				return B_ERROR;
520 			break;
521 
522 		case PPPC_ENABLE_REPORTS:
523 		{
524 			if (length < sizeof(ppp_report_request) || !data)
525 				return B_ERROR;
526 
527 			LockerHelper locker(fLock);
528 			ppp_report_request *request = (ppp_report_request*) data;
529 			// first, we send an initial state report
530 			if (request->type == PPP_CONNECTION_REPORT) {
531 				ppp_report_packet report;
532 				report.type = PPP_CONNECTION_REPORT;
533 				report.code = StateMachine().fLastConnectionReportCode;
534 				report.length = sizeof(fID);
535 				KPPPReportManager::SendReport(request->thread, &report);
536 				if (request->flags & PPP_REMOVE_AFTER_REPORT)
537 					return B_OK;
538 			}
539 			ReportManager().EnableReports(request->type, request->thread,
540 				request->flags);
541 			break;
542 		}
543 
544 		case PPPC_DISABLE_REPORTS:
545 		{
546 			if (length < sizeof(ppp_report_request) || !data)
547 				return B_ERROR;
548 
549 			ppp_report_request *request = (ppp_report_request*) data;
550 			ReportManager().DisableReports(request->type, request->thread);
551 			break;
552 		}
553 
554 		case PPPC_GET_STATISTICS:
555 			if (length < sizeof(ppp_statistics) || !data)
556 				return B_ERROR;
557 
558 			memcpy(data, &fStatistics, sizeof(ppp_statistics));
559 			break;
560 
561 		case PPPC_CONTROL_DEVICE:
562 		{
563 			if (length < sizeof(ppp_control_info) || !data)
564 				return B_ERROR;
565 
566 			ppp_control_info *control = (ppp_control_info*) data;
567 			if (control->index != 0 || !Device())
568 				return B_BAD_INDEX;
569 
570 			return Device()->Control(control->op, control->data, control->length);
571 		}
572 
573 		case PPPC_CONTROL_PROTOCOL:
574 		{
575 			if (length < sizeof(ppp_control_info) || !data)
576 				return B_ERROR;
577 
578 			ppp_control_info *control = (ppp_control_info*) data;
579 			KPPPProtocol *protocol = ProtocolAt(control->index);
580 			if (!protocol)
581 				return B_BAD_INDEX;
582 
583 			return protocol->Control(control->op, control->data, control->length);
584 		}
585 
586 		case PPPC_CONTROL_OPTION_HANDLER:
587 		{
588 			if (length < sizeof(ppp_control_info) || !data)
589 				return B_ERROR;
590 
591 			ppp_control_info *control = (ppp_control_info*) data;
592 			KPPPOptionHandler *optionHandler = LCP().OptionHandlerAt(control->index);
593 			if (!optionHandler)
594 				return B_BAD_INDEX;
595 
596 			return optionHandler->Control(control->op, control->data,
597 				control->length);
598 		}
599 
600 		case PPPC_CONTROL_LCP_EXTENSION:
601 		{
602 			if (length < sizeof(ppp_control_info) || !data)
603 				return B_ERROR;
604 
605 			ppp_control_info *control = (ppp_control_info*) data;
606 			KPPPLCPExtension *lcpExtension = LCP().LCPExtensionAt(control->index);
607 			if (!lcpExtension)
608 				return B_BAD_INDEX;
609 
610 			return lcpExtension->Control(control->op, control->data,
611 				control->length);
612 		}
613 
614 		case PPPC_CONTROL_CHILD:
615 		{
616 			if (length < sizeof(ppp_control_info) || !data)
617 				return B_ERROR;
618 
619 			ppp_control_info *control = (ppp_control_info*) data;
620 			KPPPInterface *child = ChildAt(control->index);
621 			if (!child)
622 				return B_BAD_INDEX;
623 
624 			return child->Control(control->op, control->data, control->length);
625 		}
626 
627 		default:
628 			return B_BAD_VALUE;
629 	}
630 
631 	return B_OK;
632 }
633 
634 
635 /*!	\brief Sets a new device for this interface.
636 
637 	A device add-on should call this method to register itself. The best place to do
638 	this is in your module's \c add_to() function.
639 
640 	\param device The device object.
641 
642 	\return \c true if successful or \c false otherwise.
643 
644 	\sa KPPPDevice
645 	\sa kppp_module_info
646 */
647 bool
648 KPPPInterface::SetDevice(KPPPDevice *device)
649 {
650 	TRACE("KPPPInterface: SetDevice(%p)\n", device);
651 
652 	if (device && &device->Interface() != this)
653 		return false;
654 
655 	if (IsMultilink() && !Parent())
656 		return false;
657 			// main interfaces do not have devices
658 
659 	LockerHelper locker(fLock);
660 
661 	if (Phase() != PPP_DOWN_PHASE)
662 		return false;
663 			// a running connection may not change
664 
665 	if (fDevice && (IsUp() || fDevice->IsUp()))
666 		Down();
667 
668 	fDevice = device;
669 	SetNext(device);
670 
671 	if (fDevice)
672 		fMRU = fDevice->MTU() - 2;
673 
674 	CalculateInterfaceMTU();
675 	CalculateBaudRate();
676 
677 	return true;
678 }
679 
680 
681 /*!	\brief Adds a new protocol to this interface.
682 
683 	NOTE: You can only add protocols in \c PPP_DOWN_PHASE. \n
684 	A protocol add-on should call this method to register itself. The best place to do
685 	this is in your module's \c add_to() function.
686 
687 	\param protocol The protocol object.
688 
689 	\return \c true if successful or \c false otherwise.
690 
691 	\sa KPPPProtocol
692 	\sa kppp_module_info
693 */
694 bool
695 KPPPInterface::AddProtocol(KPPPProtocol *protocol)
696 {
697 	// Find insert position after the last protocol
698 	// with the same level.
699 
700 	TRACE("KPPPInterface: AddProtocol(%X)\n",
701 		protocol ? protocol->ProtocolNumber() : 0);
702 
703 	if (!protocol || &protocol->Interface() != this
704 			|| protocol->Level() == PPP_INTERFACE_LEVEL)
705 		return false;
706 
707 	LockerHelper locker(fLock);
708 
709 	if (Phase() != PPP_DOWN_PHASE)
710 		return false;
711 			// a running connection may not change
712 
713 	KPPPProtocol *current = fFirstProtocol, *previous = NULL;
714 
715 	while (current) {
716 		if (current->Level() < protocol->Level())
717 			break;
718 
719 		previous = current;
720 		current = current->NextProtocol();
721 	}
722 
723 	if (!current) {
724 		if (!previous)
725 			fFirstProtocol = protocol;
726 		else
727 			previous->SetNextProtocol(protocol);
728 
729 		// set up the last protocol in the chain
730 		protocol->SetNextProtocol(NULL);
731 			// this also sets next to NULL
732 		protocol->SetNext(this);
733 			// we need to set us as the next layer for the last protocol
734 	} else {
735 		protocol->SetNextProtocol(current);
736 
737 		if (!previous)
738 			fFirstProtocol = protocol;
739 		else
740 			previous->SetNextProtocol(protocol);
741 	}
742 
743 	if (protocol->Level() < PPP_PROTOCOL_LEVEL)
744 		CalculateInterfaceMTU();
745 
746 	if (IsUp() || Phase() >= protocol->ActivationPhase())
747 		protocol->Up();
748 
749 	return true;
750 }
751 
752 
753 /*!	\brief Removes a protocol from this interface.
754 
755 	NOTE: You can only remove protocols in \c PPP_DOWN_PHASE. \n
756 	A protocol add-on should call this method to remove itself explicitly from the
757 	interface. \n
758 	Normally, this method is called in KPPPProtocol's destructor. Do not call it
759 	yourself unless you know what you do!
760 
761 	\param protocol The protocol object.
762 
763 	\return \c true if successful or \c false otherwise.
764 */
765 bool
766 KPPPInterface::RemoveProtocol(KPPPProtocol *protocol)
767 {
768 	TRACE("KPPPInterface: RemoveProtocol(%X)\n",
769 		protocol ? protocol->ProtocolNumber() : 0);
770 
771 	LockerHelper locker(fLock);
772 
773 	if (Phase() != PPP_DOWN_PHASE)
774 		return false;
775 			// a running connection may not change
776 
777 	KPPPProtocol *current = fFirstProtocol, *previous = NULL;
778 
779 	while (current) {
780 		if (current == protocol) {
781 			if (!protocol->IsDown())
782 				protocol->Down();
783 
784 			if (previous) {
785 				previous->SetNextProtocol(current->NextProtocol());
786 
787 				// set us as next layer if needed
788 				if (!previous->Next())
789 					previous->SetNext(this);
790 			} else
791 				fFirstProtocol = current->NextProtocol();
792 
793 			current->SetNextProtocol(NULL);
794 
795 			CalculateInterfaceMTU();
796 
797 			return true;
798 		}
799 
800 		previous = current;
801 		current = current->NextProtocol();
802 	}
803 
804 	return false;
805 }
806 
807 
808 //!	Returns the number of protocol modules belonging to this interface.
809 int32
810 KPPPInterface::CountProtocols() const
811 {
812 	LockerHelper locker(fLock);
813 
814 	KPPPProtocol *protocol = FirstProtocol();
815 
816 	int32 count = 0;
817 	for (; protocol; protocol = protocol->NextProtocol())
818 		++count;
819 
820 	return count;
821 }
822 
823 
824 //!	Returns the protocol at the given \a index or \c NULL if it could not be found.
825 KPPPProtocol*
826 KPPPInterface::ProtocolAt(int32 index) const
827 {
828 	LockerHelper locker(fLock);
829 
830 	KPPPProtocol *protocol = FirstProtocol();
831 
832 	int32 currentIndex = 0;
833 	for (; protocol && currentIndex != index; protocol = protocol->NextProtocol())
834 		++currentIndex;
835 
836 	return protocol;
837 }
838 
839 
840 /*!	\brief Returns the protocol object responsible for a given protocol number.
841 
842 	\param protocolNumber The protocol number that the object should handle.
843 	\param start (Optional): Start with this protocol. Can be used for iteration.
844 
845 	\return Either the object that was found or \c NULL.
846 */
847 KPPPProtocol*
848 KPPPInterface::ProtocolFor(uint16 protocolNumber, KPPPProtocol *start) const
849 {
850 	TRACE("KPPPInterface: ProtocolFor(%X)\n", protocolNumber);
851 
852 	LockerHelper locker(fLock);
853 
854 	KPPPProtocol *current = start ? start : FirstProtocol();
855 
856 	for (; current; current = current->NextProtocol()) {
857 		if (current->ProtocolNumber() == protocolNumber
858 				|| (current->Flags() & PPP_INCLUDES_NCP
859 					&& (current->ProtocolNumber() & 0x7FFF)
860 						== (protocolNumber & 0x7FFF)))
861 			return current;
862 	}
863 
864 	return NULL;
865 }
866 
867 
868 //!	Adds a new child interface (used for multilink interfaces).
869 bool
870 KPPPInterface::AddChild(KPPPInterface *child)
871 {
872 	TRACE("KPPPInterface: AddChild(%lX)\n", child ? child->ID() : 0);
873 
874 	if (!child)
875 		return false;
876 
877 	LockerHelper locker(fLock);
878 
879 	if (fChildren.HasItem(child) || !fChildren.AddItem(child))
880 		return false;
881 
882 	child->SetParent(this);
883 
884 	return true;
885 }
886 
887 
888 //!	Removes a new child from this interface (used for multilink interfaces).
889 bool
890 KPPPInterface::RemoveChild(KPPPInterface *child)
891 {
892 	TRACE("KPPPInterface: RemoveChild(%lX)\n", child ? child->ID() : 0);
893 
894 	LockerHelper locker(fLock);
895 
896 	if (!fChildren.RemoveItem(child))
897 		return false;
898 
899 	child->SetParent(NULL);
900 
901 	// parents cannot exist without their children
902 	if (CountChildren() == 0 && fManager && Ifnet())
903 		Delete();
904 
905 	return true;
906 }
907 
908 
909 //!	Returns the child interface at the given \a index (used for multilink interfaces).
910 KPPPInterface*
911 KPPPInterface::ChildAt(int32 index) const
912 {
913 	TRACE("KPPPInterface: ChildAt(%ld)\n", index);
914 
915 	LockerHelper locker(fLock);
916 
917 	KPPPInterface *child = fChildren.ItemAt(index);
918 
919 	if (child == fChildren.GetDefaultItem())
920 		return NULL;
921 
922 	return child;
923 }
924 
925 
926 //!	Enables or disables the auto-reconnect feture.
927 void
928 KPPPInterface::SetAutoReconnect(bool autoReconnect)
929 {
930 	TRACE("KPPPInterface: SetAutoReconnect(%s)\n", autoReconnect ? "true" : "false");
931 
932 	if (Mode() != PPP_CLIENT_MODE)
933 		return;
934 
935 	fAutoReconnect = autoReconnect;
936 }
937 
938 
939 //!	Enables or disables the connect-on-demand feature.
940 void
941 KPPPInterface::SetConnectOnDemand(bool connectOnDemand)
942 {
943 	// All protocols must check if ConnectOnDemand was enabled/disabled after this
944 	// interface went down. This is the only situation where a change is relevant.
945 
946 	TRACE("KPPPInterface: SetConnectOnDemand(%s)\n", connectOnDemand ? "true" : "false");
947 
948 	LockerHelper locker(fLock);
949 
950 	// Only clients support ConnectOnDemand.
951 	if (Mode() != PPP_CLIENT_MODE) {
952 		TRACE("KPPPInterface::SetConnectOnDemand(): Wrong mode!\n");
953 		fConnectOnDemand = false;
954 		return;
955 	} else if (DoesConnectOnDemand() == connectOnDemand)
956 		return;
957 
958 	fConnectOnDemand = connectOnDemand;
959 
960 	// Do not allow changes when we are disconnected (only main interfaces).
961 	// This would make no sense because
962 	// - enabling: this cannot happen because hidden interfaces are deleted if they
963 	//    could not establish a connection (the user cannot access hidden interfaces)
964 	// - disabling: the interface disappears as seen from the user, so we delete it
965 	if (!Parent() && State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE) {
966 		if (!connectOnDemand)
967 			Delete();
968 				// as long as the protocols were not configured we can just delete us
969 
970 		return;
971 	}
972 
973 	// check if we need to set/unset flags
974 	if (connectOnDemand) {
975 		if (Ifnet())
976 			Ifnet()->if_flags |= IFF_UP;
977 	} else if (!connectOnDemand && Phase() < PPP_ESTABLISHED_PHASE) {
978 		if (Ifnet())
979 			Ifnet()->if_flags &= ~IFF_UP;
980 	}
981 }
982 
983 
984 //!	Sets whether the user is asked before establishing the connection.
985 void
986 KPPPInterface::SetAskBeforeConnecting(bool ask)
987 {
988 	LockerHelper locker(fLock);
989 
990 	bool old = fAskBeforeConnecting;
991 	fAskBeforeConnecting = ask;
992 
993 	if (old && fAskBeforeConnecting == false && State() == PPP_STARTING_STATE
994 			&& Phase() == PPP_DOWN_PHASE) {
995 		locker.UnlockNow();
996 		StateMachine().ContinueOpenEvent();
997 	}
998 }
999 
1000 
1001 //!	Sets Protocol-Field-Compression options.
1002 bool
1003 KPPPInterface::SetPFCOptions(uint8 pfcOptions)
1004 {
1005 	TRACE("KPPPInterface: SetPFCOptions(0x%X)\n", pfcOptions);
1006 
1007 	LockerHelper locker(fLock);
1008 
1009 	if (PFCOptions() & PPP_FREEZE_PFC_OPTIONS)
1010 		return false;
1011 
1012 	fPFCOptions = pfcOptions;
1013 	return true;
1014 }
1015 
1016 
1017 /*!	\brief Brings this interface up.
1018 
1019 	\c Down() overrides all \c Up() requests. \n
1020 	This method runs an asynchronous process (it returns immediately).
1021 
1022 	\return \c false on error.
1023 */
1024 bool
1025 KPPPInterface::Up()
1026 {
1027 	TRACE("KPPPInterface: Up()\n");
1028 
1029 	if (InitCheck() != B_OK || Phase() == PPP_TERMINATION_PHASE)
1030 		return false;
1031 
1032 	if (IsUp())
1033 		return true;
1034 
1035 	LockerHelper locker(fLock);
1036 	StateMachine().OpenEvent();
1037 
1038 	return true;
1039 }
1040 
1041 
1042 /*!	\brief Brings this interface down.
1043 
1044 	\c Down() overrides all \c Up() requests. \n
1045 	This method runs an asynchronous process (it returns immediately).
1046 
1047 	\return \c false on error.
1048 */
1049 bool
1050 KPPPInterface::Down()
1051 {
1052 	TRACE("KPPPInterface: Down()\n");
1053 
1054 	if (InitCheck() != B_OK)
1055 		return false;
1056 	else if (State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE)
1057 		return true;
1058 
1059 	send_data_with_timeout(fReconnectThread, 0, NULL, 0, 200);
1060 		// tell the reconnect thread to abort its attempt (if it's still waiting)
1061 
1062 	LockerHelper locker(fLock);
1063 	StateMachine().CloseEvent();
1064 
1065 	return true;
1066 }
1067 
1068 
1069 //!	Waits for connection establishment. Returns true if successful.
1070 bool
1071 KPPPInterface::WaitForConnection()
1072 {
1073 	TRACE("KPPPInterface: WaitForConnection()\n");
1074 
1075 	if (InitCheck() != B_OK)
1076 		return false;
1077 
1078 	ReportManager().EnableReports(PPP_CONNECTION_REPORT, find_thread(NULL));
1079 
1080 	ppp_report_packet report;
1081 	thread_id sender;
1082 	bool successful = false;
1083 	while (true) {
1084 		if (receive_data(&sender, &report, sizeof(report)) != PPP_REPORT_CODE)
1085 			continue;
1086 
1087 		if (report.type == PPP_DESTRUCTION_REPORT)
1088 			break;
1089 		else if (report.type != PPP_CONNECTION_REPORT)
1090 			continue;
1091 
1092 		if (report.code == PPP_REPORT_UP_SUCCESSFUL) {
1093 			successful = true;
1094 			break;
1095 		} else if (report.code == PPP_REPORT_DOWN_SUCCESSFUL)
1096 			break;
1097 	}
1098 
1099 	ReportManager().DisableReports(PPP_CONNECTION_REPORT, find_thread(NULL));
1100 	return successful;
1101 }
1102 
1103 
1104 /*!	\brief Loads modules specified in the settings structure.
1105 
1106 	\param settings PPP interface description file format settings.
1107 	\param start Index of driver_parameter to start with.
1108 	\param count Number of driver_parameters to look at.
1109 
1110 	\return \c true if successful or \c false otherwise.
1111 */
1112 bool
1113 KPPPInterface::LoadModules(driver_settings *settings, int32 start, int32 count)
1114 {
1115 	TRACE("KPPPInterface: LoadModules()\n");
1116 
1117 	if (Phase() != PPP_DOWN_PHASE)
1118 		return false;
1119 			// a running connection may not change
1120 
1121 	ppp_module_key_type type;
1122 		// which type key was used for loading this module?
1123 
1124 	const char *name = NULL;
1125 
1126 	// multilink handling
1127 	for (int32 index = start;
1128 			index < settings->parameter_count && index < (start + count); index++) {
1129 		if (!strcasecmp(settings->parameters[index].name, PPP_MULTILINK_KEY)
1130 				&& settings->parameters[index].value_count > 0) {
1131 			if (!LoadModule(settings->parameters[index].values[0],
1132 					&settings->parameters[index], PPP_MULTILINK_KEY_TYPE))
1133 				return false;
1134 			break;
1135 		}
1136 	}
1137 
1138 	// are we a multilink main interface?
1139 	if (IsMultilink() && !Parent()) {
1140 		// main interfaces only load the multilink module
1141 		// and create a child using their settings
1142 		fManager->CreateInterface(settings, ID());
1143 		return true;
1144 	}
1145 
1146 	for (int32 index = start;
1147 			index < settings->parameter_count && index < start + count; index++) {
1148 		type = PPP_UNDEFINED_KEY_TYPE;
1149 
1150 		name = settings->parameters[index].name;
1151 
1152 		if (!strcasecmp(name, PPP_LOAD_MODULE_KEY))
1153 			type = PPP_LOAD_MODULE_KEY_TYPE;
1154 		else if (!strcasecmp(name, PPP_DEVICE_KEY))
1155 			type = PPP_DEVICE_KEY_TYPE;
1156 		else if (!strcasecmp(name, PPP_PROTOCOL_KEY))
1157 			type = PPP_PROTOCOL_KEY_TYPE;
1158 		else if (!strcasecmp(name, PPP_AUTHENTICATOR_KEY))
1159 			type = PPP_AUTHENTICATOR_KEY_TYPE;
1160 
1161 		if (type >= 0)
1162 			for (int32 value_id = 0; value_id < settings->parameters[index].value_count;
1163 					value_id++)
1164 				if (!LoadModule(settings->parameters[index].values[value_id],
1165 						&settings->parameters[index], type))
1166 					return false;
1167 	}
1168 
1169 	return true;
1170 }
1171 
1172 
1173 /*!	\brief Loads a specific module.
1174 
1175 	\param name Name of the module.
1176 	\param parameter Module settings.
1177 	\param type Type of module.
1178 
1179 	\return \c true if successful or \c false otherwise.
1180 */
1181 bool
1182 KPPPInterface::LoadModule(const char *name, driver_parameter *parameter,
1183 	ppp_module_key_type type)
1184 {
1185 	TRACE("KPPPInterface: LoadModule(%s)\n", name ? name : "XXX: NO NAME");
1186 
1187 	if (Phase() != PPP_DOWN_PHASE)
1188 		return false;
1189 			// a running connection may not change
1190 
1191 	if (!name || strlen(name) > B_FILE_NAME_LENGTH)
1192 		return false;
1193 
1194 	char *moduleName = new char[B_PATH_NAME_LENGTH];
1195 
1196 	sprintf(moduleName, "%s/%s", PPP_MODULES_PATH, name);
1197 
1198 	ppp_module_info *module;
1199 	if (get_module(moduleName, (module_info**) &module) != B_OK) {
1200 		delete[] moduleName;
1201 		return false;
1202 	}
1203 
1204 	// add the module to the list of loaded modules
1205 	// for putting them on our destruction
1206 	fModules.AddItem(moduleName);
1207 
1208 	return module->add_to(Parent() ? *Parent() : *this, this, parameter, type);
1209 }
1210 
1211 
1212 //!	Always returns true.
1213 bool
1214 KPPPInterface::IsAllowedToSend() const
1215 {
1216 	return true;
1217 }
1218 
1219 
1220 /*!	\brief Sends a packet to the device.
1221 
1222 	This brings the interface up if connect-on-demand is enabled and we are not
1223 	connected. \n
1224 	PFC encoding is handled here. \n
1225 	NOTE: In order to prevent interface destruction while sending you must either
1226 	hold a refcount for this interface or make sure it is locked.
1227 
1228 	\param packet The packet.
1229 	\param protocolNumber The packet's protocol number.
1230 
1231 	\return
1232 		- \c B_OK: Sending was successful.
1233 		- \c B_ERROR: Some error occured.
1234 */
1235 status_t
1236 KPPPInterface::Send(struct mbuf *packet, uint16 protocolNumber)
1237 {
1238 	TRACE("KPPPInterface: Send(0x%X)\n", protocolNumber);
1239 
1240 	if (!packet)
1241 		return B_ERROR;
1242 
1243 	// we must pass the basic tests like:
1244 	// do we have a device?
1245 	// did we load all modules?
1246 	if (InitCheck() != B_OK) {
1247 		m_freem(packet);
1248 		return B_ERROR;
1249 	}
1250 
1251 	// go up if ConnectOnDemand is enabled and we are disconnected
1252 	// TODO: our new netstack will simplify ConnectOnDemand handling, so
1253 	// we do not have to handle it here
1254 	if ((protocolNumber != PPP_LCP_PROTOCOL && DoesConnectOnDemand()
1255 			&& (Phase() == PPP_DOWN_PHASE
1256 				|| Phase() == PPP_ESTABLISHMENT_PHASE)
1257 			&& !Up()) || !WaitForConnection()) {
1258 		m_freem(packet);
1259 		return B_ERROR;
1260 	}
1261 
1262 	// find the protocol handler for the current protocol number
1263 	KPPPProtocol *protocol = ProtocolFor(protocolNumber);
1264 	while (protocol && !protocol->IsEnabled())
1265 		protocol = protocol->NextProtocol() ?
1266 			ProtocolFor(protocolNumber, protocol->NextProtocol()) : NULL;
1267 
1268 #if DEBUG
1269 	if (!protocol)
1270 		TRACE("KPPPInterface::Send(): no protocol found!\n");
1271 	else if (!Device()->IsUp())
1272 		TRACE("KPPPInterface::Send(): device is not up!\n");
1273 	else if (!protocol->IsEnabled())
1274 		TRACE("KPPPInterface::Send(): protocol not enabled!\n");
1275 	else if (!IsProtocolAllowed(*protocol))
1276 		TRACE("KPPPInterface::Send(): protocol not allowed to send!\n");
1277 	else
1278 		TRACE("KPPPInterface::Send(): protocol allowed\n");
1279 #endif
1280 
1281 	// make sure that protocol is allowed to send and everything is up
1282 	if (!Device()->IsUp() || !protocol || !protocol->IsEnabled()
1283 			|| !IsProtocolAllowed(*protocol)) {
1284 		ERROR("KPPPInterface::Send(): cannot send!\n");
1285 		m_freem(packet);
1286 		return B_ERROR;
1287 	}
1288 
1289 	// encode in ppp frame and consider using PFC
1290 	if (UseLocalPFC() && protocolNumber & 0xFF00 == 0) {
1291 		M_PREPEND(packet, 1);
1292 
1293 		if (packet == NULL)
1294 			return B_ERROR;
1295 
1296 		uint8 *header = mtod(packet, uint8*);
1297 		*header = protocolNumber & 0xFF;
1298 	} else {
1299 		M_PREPEND(packet, 2);
1300 
1301 		if (packet == NULL)
1302 			return B_ERROR;
1303 
1304 		// set protocol (the only header field)
1305 		protocolNumber = htons(protocolNumber);
1306 		uint16 *header = mtod(packet, uint16*);
1307 		*header = protocolNumber;
1308 	}
1309 
1310 	// pass to device if we're either not a multilink interface or a child interface
1311 	if (!IsMultilink() || Parent()) {
1312 		// check if packet is too big for device
1313 		uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len :
1314 			packet->m_len;
1315 
1316 		if (length > MRU()) {
1317 			m_freem(packet);
1318 			return B_ERROR;
1319 		}
1320 
1321 		atomic_add64(&fStatistics.bytesSent, length);
1322 		atomic_add64(&fStatistics.packetsSent, 1);
1323 		return SendToNext(packet, 0);
1324 			// this is normally the device, but there can be something inbetween
1325 	} else {
1326 		// the multilink protocol should have sent it to some child interface
1327 		m_freem(packet);
1328 		return B_ERROR;
1329 	}
1330 }
1331 
1332 
1333 /*!	\brief Receives a packet.
1334 
1335 	Encapsulation protocols may use this method to pass encapsulated packets to the
1336 	PPP interface. Packets will be handled as if they were raw packets that came
1337 	directly from the device via \c ReceiveFromDevice(). \n
1338 	If no handler could be found in this interface the parent's \c Receive() method
1339 	is called.
1340 
1341 	\param packet The packet.
1342 	\param protocolNumber The packet's protocol number.
1343 
1344 	\return
1345 		- \c B_OK: Receiving was successful.
1346 		- \c B_ERROR: Some error occured.
1347 		- \c PPP_REJECTED: No protocol handler could be found for this packet.
1348 		- \c PPP_DISCARDED: The protocol handler(s) did not handle this packet.
1349 */
1350 status_t
1351 KPPPInterface::Receive(struct mbuf *packet, uint16 protocolNumber)
1352 {
1353 	TRACE("KPPPInterface: Receive(0x%X)\n", protocolNumber);
1354 
1355 	if (!packet)
1356 		return B_ERROR;
1357 
1358 	LockerHelper locker(fLock);
1359 
1360 	int32 result = PPP_REJECTED;
1361 		// assume we have no handler
1362 
1363 	// Set our interface as the receiver.
1364 	// The real netstack protocols (IP, IPX, etc.) might get confused if our
1365 	// interface is a main interface and at the same time not registered
1366 	// because then there is no receiver interface.
1367 	// PPP NCPs should be aware of that!
1368 	if (packet->m_flags & M_PKTHDR && Ifnet() != NULL)
1369 		packet->m_pkthdr.rcvif = Ifnet();
1370 
1371 	// Find handler and let it parse the packet.
1372 	// The handler does need not be up because if we are a server
1373 	// the handler might be upped by this packet.
1374 	// If authenticating we only allow authentication phase protocols.
1375 	KPPPProtocol *protocol = ProtocolFor(protocolNumber);
1376 	for (; protocol;
1377 			protocol = protocol->NextProtocol() ?
1378 				ProtocolFor(protocolNumber, protocol->NextProtocol()) : NULL) {
1379 		TRACE("KPPPInterface::Receive(): trying protocol\n");
1380 
1381 		if (!protocol->IsEnabled() || !IsProtocolAllowed(*protocol))
1382 			continue;
1383 				// skip handler if disabled or not allowed
1384 
1385 		result = protocol->Receive(packet, protocolNumber);
1386 		if (result == PPP_UNHANDLED)
1387 			continue;
1388 
1389 		return result;
1390 	}
1391 
1392 	TRACE("KPPPInterface::Receive(): trying parent\n");
1393 
1394 	// maybe the parent interface can handle the packet
1395 	if (Parent())
1396 		return Parent()->Receive(packet, protocolNumber);
1397 
1398 	if (result == PPP_UNHANDLED) {
1399 		m_freem(packet);
1400 		return PPP_DISCARDED;
1401 	} else {
1402 		StateMachine().RUCEvent(packet, protocolNumber);
1403 		return PPP_REJECTED;
1404 	}
1405 }
1406 
1407 
1408 /*!	\brief Receives a base PPP packet from the device.
1409 
1410 	KPPPDevice should call this method when it receives a packet. \n
1411 	PFC decoding is handled here.
1412 
1413 	\param packet The packet.
1414 
1415 	\return
1416 		- \c B_OK: Receiving was successful.
1417 		- \c B_ERROR: Some error occured.
1418 		- \c PPP_REJECTED: No protocol handler could be found for this packet.
1419 		- \c PPP_DISCARDED: The protocol handler(s) did not handle this packet.
1420 */
1421 status_t
1422 KPPPInterface::ReceiveFromDevice(struct mbuf *packet)
1423 {
1424 	TRACE("KPPPInterface: ReceiveFromDevice()\n");
1425 
1426 	if (!packet)
1427 		return B_ERROR;
1428 
1429 	if (InitCheck() != B_OK) {
1430 		m_freem(packet);
1431 		return B_ERROR;
1432 	}
1433 
1434 	uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len :
1435 		packet->m_len;
1436 
1437 	// decode ppp frame and recognize PFC
1438 	uint16 protocolNumber = *mtod(packet, uint8*);
1439 	if (protocolNumber & 1) {
1440 		m_adj(packet, 1);
1441 	} else {
1442 		protocolNumber = ntohs(*mtod(packet, uint16*));
1443 		m_adj(packet, 2);
1444 	}
1445 
1446 	atomic_add64(&fStatistics.bytesReceived, length);
1447 	atomic_add64(&fStatistics.packetsReceived, 1);
1448 	return Receive(packet, protocolNumber);
1449 }
1450 
1451 
1452 //!	Manages Pulse() calls for all add-ons and hanldes idle-disconnection.
1453 void
1454 KPPPInterface::Pulse()
1455 {
1456 	LockerHelper locker(fLock);
1457 
1458 	if (Device())
1459 		Device()->Pulse();
1460 
1461 	KPPPProtocol *protocol = FirstProtocol();
1462 	for (; protocol; protocol = protocol->NextProtocol())
1463 		protocol->Pulse();
1464 
1465 	uint32 currentTime = real_time_clock();
1466 	if (fUpdateIdleSince) {
1467 		fIdleSince = currentTime;
1468 		fUpdateIdleSince = false;
1469 	}
1470 
1471 	// check our idle time and disconnect if needed
1472 	if (fDisconnectAfterIdleSince > 0 && fIdleSince != 0
1473 			&& fIdleSince - currentTime >= fDisconnectAfterIdleSince)
1474 		StateMachine().CloseEvent();
1475 }
1476 
1477 
1478 //!	Registers an ifnet structure for this interface.
1479 bool
1480 KPPPInterface::RegisterInterface()
1481 {
1482 	TRACE("KPPPInterface: RegisterInterface()\n");
1483 
1484 	if (fIfnet)
1485 		return true;
1486 			// we are already registered
1487 
1488 	LockerHelper locker(fLock);
1489 
1490 	// only MainInterfaces get an ifnet
1491 	if (IsMultilink() && Parent() && Parent()->RegisterInterface())
1492 		return true;
1493 
1494 	if (!fManager)
1495 		return false;
1496 
1497 	fIfnet = fManager->RegisterInterface(ID());
1498 
1499 	if (!fIfnet)
1500 		return false;
1501 
1502 	if (DoesConnectOnDemand())
1503 		fIfnet->if_flags |= IFF_UP;
1504 
1505 	CalculateInterfaceMTU();
1506 	CalculateBaudRate();
1507 
1508 	return true;
1509 }
1510 
1511 
1512 //!	Unregisters this interface's ifnet structure.
1513 bool
1514 KPPPInterface::UnregisterInterface()
1515 {
1516 	TRACE("KPPPInterface: UnregisterInterface()\n");
1517 
1518 	if (!fIfnet)
1519 		return true;
1520 			// we are already unregistered
1521 
1522 	LockerHelper locker(fLock);
1523 
1524 	// only MainInterfaces get an ifnet
1525 	if (IsMultilink() && Parent())
1526 		return true;
1527 
1528 	if (!fManager)
1529 		return false;
1530 
1531 	fManager->UnregisterInterface(ID());
1532 		// this will delete fIfnet, so do not access it anymore!
1533 	fIfnet = NULL;
1534 
1535 	return true;
1536 }
1537 
1538 
1539 //!	Called by KPPPManager: manager routes stack ioctls to the corresponding interface.
1540 status_t
1541 KPPPInterface::StackControl(uint32 op, void *data)
1542 {
1543 	TRACE("KPPPInterface: StackControl(0x%lX)\n", op);
1544 
1545 	switch (op) {
1546 		default:
1547 			return StackControlEachHandler(op, data);
1548 	}
1549 
1550 	return B_OK;
1551 }
1552 
1553 
1554 //!	Utility class used by ControlEachHandler().
1555 template<class T>
1556 class CallStackControl {
1557 	public:
1558 		inline CallStackControl(uint32 op, void *data, status_t& result)
1559 			: fOp(op), fData(data), fResult(result) {}
1560 		inline void operator() (T *item)
1561 			{
1562 				if (!item || !item->IsEnabled())
1563 					return;
1564 				status_t tmp = item->StackControl(fOp, fData);
1565 				if (tmp == B_OK && fResult == B_BAD_VALUE)
1566 					fResult = B_OK;
1567 				else if (tmp != B_BAD_VALUE)
1568 					fResult = tmp;
1569 			}
1570 	private:
1571 		uint32 fOp;
1572 		void *fData;
1573 		status_t& fResult;
1574 };
1575 
1576 /*!	\brief This calls Control() with the given parameters for each add-on.
1577 
1578 	\return
1579 		- \c B_OK: All handlers returned B_OK.
1580 		- \c B_BAD_VALUE: No handler was found.
1581 		- Any other value: Error code which was returned by the last failing handler.
1582 */
1583 status_t
1584 KPPPInterface::StackControlEachHandler(uint32 op, void *data)
1585 {
1586 	TRACE("KPPPInterface: StackControlEachHandler(0x%lX)\n", op);
1587 
1588 	status_t result = B_BAD_VALUE, tmp;
1589 
1590 	LockerHelper locker(fLock);
1591 
1592 	KPPPProtocol *protocol = FirstProtocol();
1593 	for (; protocol; protocol = protocol->NextProtocol()) {
1594 		tmp = protocol->StackControl(op, data);
1595 		if (tmp == B_OK && result == B_BAD_VALUE)
1596 			result = B_OK;
1597 		else if (tmp != B_BAD_VALUE)
1598 			result = tmp;
1599 	}
1600 
1601 	ForEachItem(LCP().fLCPExtensions,
1602 		CallStackControl<KPPPLCPExtension>(op, data, result));
1603 	ForEachItem(LCP().fOptionHandlers,
1604 		CallStackControl<KPPPOptionHandler>(op, data, result));
1605 
1606 	return result;
1607 }
1608 
1609 
1610 //!	Recalculates the MTU from the MRU (includes encapsulation protocol overheads).
1611 void
1612 KPPPInterface::CalculateInterfaceMTU()
1613 {
1614 	TRACE("KPPPInterface: CalculateInterfaceMTU()\n");
1615 
1616 	LockerHelper locker(fLock);
1617 
1618 	fInterfaceMTU = fMRU;
1619 	fHeaderLength = 2;
1620 
1621 	// sum all headers (the protocol field is not counted)
1622 	KPPPProtocol *protocol = FirstProtocol();
1623 	for (; protocol; protocol = protocol->NextProtocol()) {
1624 		if (protocol->Level() < PPP_PROTOCOL_LEVEL)
1625 			fHeaderLength += protocol->Overhead();
1626 	}
1627 
1628 	fInterfaceMTU -= fHeaderLength;
1629 
1630 	if (Ifnet()) {
1631 		Ifnet()->if_mtu = fInterfaceMTU;
1632 		Ifnet()->if_hdrlen = fHeaderLength;
1633 	}
1634 
1635 	if (Parent())
1636 		Parent()->CalculateInterfaceMTU();
1637 }
1638 
1639 
1640 //!	Recalculates the baud rate.
1641 void
1642 KPPPInterface::CalculateBaudRate()
1643 {
1644 	TRACE("KPPPInterface: CalculateBaudRate()\n");
1645 
1646 	LockerHelper locker(fLock);
1647 
1648 	if (!Ifnet())
1649 		return;
1650 
1651 	if (Device())
1652 		fIfnet->if_baudrate = max_c(Device()->InputTransferRate(),
1653 			Device()->OutputTransferRate());
1654 	else {
1655 		fIfnet->if_baudrate = 0;
1656 		for (int32 index = 0; index < CountChildren(); index++)
1657 			if (ChildAt(index)->Ifnet())
1658 				fIfnet->if_baudrate += ChildAt(index)->Ifnet()->if_baudrate;
1659 	}
1660 }
1661 
1662 
1663 //!	Reconnects. Waits a given delay (in miliseconds) before reconnecting.
1664 void
1665 KPPPInterface::Reconnect(uint32 delay)
1666 {
1667 	TRACE("KPPPInterface: Reconnect(%ld)\n", delay);
1668 
1669 	LockerHelper locker(fLock);
1670 
1671 	if (fReconnectThread != -1)
1672 		return;
1673 
1674 	++fConnectAttempt;
1675 
1676 	// start a new thread that calls our Up() method
1677 	reconnect_info info;
1678 	info.interface = this;
1679 	info.thread = &fReconnectThread;
1680 	info.delay = delay;
1681 
1682 	fReconnectThread = spawn_kernel_thread(reconnect_thread,
1683 		"KPPPInterface: reconnect_thread", B_NORMAL_PRIORITY, NULL);
1684 
1685 	resume_thread(fReconnectThread);
1686 
1687 	send_data(fReconnectThread, 0, &info, sizeof(reconnect_info));
1688 }
1689 
1690 
1691 status_t
1692 reconnect_thread(void *data)
1693 {
1694 	reconnect_info info;
1695 	thread_id sender;
1696 	int32 code;
1697 
1698 	receive_data(&sender, &info, sizeof(reconnect_info));
1699 
1700 	// we try to receive data instead of snooze, so we can quit on destruction
1701 	if (receive_data_with_timeout(&sender, &code, NULL, 0, info.delay) == B_OK) {
1702 		*info.thread = -1;
1703 		return B_OK;
1704 	}
1705 
1706 	info.interface->Up();
1707 	*info.thread = -1;
1708 
1709 	return B_OK;
1710 }
1711