xref: /haiku/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPInterface.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
1 /*
2  * Copyright 2003-2005, 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,
81 		KPPPInterface *parent)
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 	++fDeleteCounter;
239 
240 	// tell protocols to uninit (remove routes, etc.)
241 	KPPPProtocol *protocol = FirstProtocol();
242 	for(; protocol; protocol = protocol->NextProtocol())
243 		protocol->Uninit();
244 
245 	// make sure we are not accessible by any thread before we continue
246 	UnregisterInterface();
247 
248 	if(fManager)
249 		fManager->RemoveInterface(ID());
250 
251 	// Call Down() until we get a lock on an interface that is down.
252 	// This lock is not released until we are actually deleted.
253 	while(true) {
254 		Down();
255 		fLock.Lock();
256 		if(State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE)
257 			break;
258 		fLock.Unlock();
259 	}
260 
261 	Report(PPP_DESTRUCTION_REPORT, 0, &fID, sizeof(ppp_interface_id));
262 		// tell all listeners that we are being destroyed
263 
264 	int32 tmp;
265 	send_data_with_timeout(fReconnectThread, 0, NULL, 0, 200);
266 		// tell thread that we are being destroyed (200ms timeout)
267 	wait_for_thread(fReconnectThread, &tmp);
268 
269 	while(CountChildren())
270 		delete ChildAt(0);
271 
272 	delete Device();
273 
274 	while(FirstProtocol()) {
275 		if(FirstProtocol() == &LCP())
276 			fFirstProtocol = fFirstProtocol->NextProtocol();
277 		else
278 			delete FirstProtocol();
279 				// destructor removes protocol from list
280 	}
281 
282 	for(int32 index = 0; index < fModules.CountItems(); index++) {
283 		put_module(fModules.ItemAt(index));
284 		delete[] fModules.ItemAt(index);
285 	}
286 
287 	free_driver_settings(fSettings);
288 
289 	if(Parent())
290 		Parent()->RemoveChild(this);
291 
292 	if(fManager)
293 		put_module(PPP_INTERFACE_MODULE_NAME);
294 }
295 
296 
297 //!	Marks interface for deletion.
298 void
299 KPPPInterface::Delete()
300 {
301 	if(atomic_add(&fDeleteCounter, 1) > 0)
302 		return;
303 			// only one thread should delete us!
304 
305 	if(fManager)
306 		fManager->DeleteInterface(ID());
307 			// This will mark us for deletion.
308 			// Any subsequent calls to delete_interface() will do nothing.
309 	else {
310 		// We were not created by the manager.
311 		// Spawn a thread that will delete us.
312 		thread_id interfaceDeleterThread
313 			= spawn_kernel_thread(interface_deleter_thread,
314 				"KPPPInterface: interface_deleter_thread", B_NORMAL_PRIORITY, this);
315 		resume_thread(interfaceDeleterThread);
316 	}
317 }
318 
319 
320 //!	Returns if interface was initialized correctly.
321 status_t
322 KPPPInterface::InitCheck() const
323 {
324 	if(fInitStatus != B_OK)
325 		return fInitStatus;
326 
327 	if(!fSettings || !fManager)
328 		return B_ERROR;
329 
330 	// sub-interfaces should have a device
331 	if(IsMultilink()) {
332 		if(Parent() && !fDevice)
333 			return B_ERROR;
334 	} else if(!fDevice)
335 		return B_ERROR;
336 
337 	return B_OK;
338 }
339 
340 
341 //!	The username used for authentication.
342 const char*
343 KPPPInterface::Username() const
344 {
345 	// this data is not available before we authenticate
346 	if(Phase() < PPP_AUTHENTICATION_PHASE)
347 		return NULL;
348 
349 	return fUsername;
350 }
351 
352 
353 //!	The password used for authentication.
354 const char*
355 KPPPInterface::Password() const
356 {
357 	// this data is not available before we authenticate
358 	if(Phase() < PPP_AUTHENTICATION_PHASE)
359 		return NULL;
360 
361 	return fPassword;
362 }
363 
364 
365 //!	Sets interface MRU.
366 bool
367 KPPPInterface::SetMRU(uint32 MRU)
368 {
369 	TRACE("KPPPInterface: SetMRU(%ld)\n", MRU);
370 
371 	if(Device() && MRU > Device()->MTU() - 2)
372 		return false;
373 
374 	LockerHelper locker(fLock);
375 
376 	fMRU = MRU;
377 
378 	CalculateInterfaceMTU();
379 
380 	return true;
381 }
382 
383 
384 //!	Returns number of bytes spent for protocol overhead. Includes device overhead.
385 uint32
386 KPPPInterface::PacketOverhead() const
387 {
388 	uint32 overhead = fHeaderLength + 2;
389 
390 	if(Device())
391 		overhead += Device()->Overhead();
392 
393 	return overhead;
394 }
395 
396 
397 /*!	\brief Allows accessing additional functions.
398 
399 	This is normally called by userland apps to get information about the interface.
400 
401 	\param op The op value (see ppp_control_ops enum).
402 	\param data (Optional): Additional data may be needed for this op.
403 	\param length Length of data.
404 
405 	\return
406 		- \c B_OK: \c Control() was successful.
407 		- \c B_ERROR: Either \a length is too small or data is NULL.
408 		- \c B_NOT_ALLOWED: Operation not allowed (at this point in time).
409 		- \c B_BAD_INDEX: Wrong index (e.g.: when accessing interface submodules).
410 		- \c B_BAD_VALUE: Unknown op.
411 		- Return value of submodule (when controlling one).
412 */
413 status_t
414 KPPPInterface::Control(uint32 op, void *data, size_t length)
415 {
416 	switch(op) {
417 		case PPPC_GET_INTERFACE_INFO: {
418 			if(length < sizeof(ppp_interface_info_t) || !data)
419 				return B_ERROR;
420 
421 			ppp_interface_info *info = (ppp_interface_info*) data;
422 			memset(info, 0, sizeof(ppp_interface_info_t));
423 			if(Name())
424 				strncpy(info->name, Name(), PPP_HANDLER_NAME_LENGTH_LIMIT);
425 			if(Ifnet())
426 				info->if_unit = Ifnet()->if_unit;
427 			else
428 				info->if_unit = -1;
429 			info->mode = Mode();
430 			info->state = State();
431 			info->phase = Phase();
432 			info->localAuthenticationStatus =
433 				StateMachine().LocalAuthenticationStatus();
434 			info->peerAuthenticationStatus =
435 				StateMachine().PeerAuthenticationStatus();
436 			info->localPFCState = LocalPFCState();
437 			info->peerPFCState = PeerPFCState();
438 			info->pfcOptions = PFCOptions();
439 			info->protocolsCount = CountProtocols();
440 			info->optionHandlersCount = LCP().CountOptionHandlers();
441 			info->LCPExtensionsCount = 0;
442 			info->childrenCount = CountChildren();
443 			info->MRU = MRU();
444 			info->interfaceMTU = InterfaceMTU();
445 			info->connectAttempt = fConnectAttempt;
446 			info->connectRetriesLimit = fConnectRetriesLimit;
447 			info->connectRetryDelay = ConnectRetryDelay();
448 			info->reconnectDelay = ReconnectDelay();
449 			info->connectedSince = ConnectedSince();
450 			info->idleSince = IdleSince();
451 			info->disconnectAfterIdleSince = DisconnectAfterIdleSince();
452 			info->doesConnectOnDemand = DoesConnectOnDemand();
453 			info->doesAutoReconnect = DoesAutoReconnect();
454 			info->hasDevice = Device();
455 			info->isMultilink = IsMultilink();
456 			info->hasParent = Parent();
457 		} break;
458 
459 		case PPPC_SET_USERNAME: {
460 			if(!data)
461 				return B_ERROR;
462 
463 			LockerHelper locker(fLock);
464 			// login information can only be changed before we authenticate
465 			if(Phase() >= PPP_AUTHENTICATION_PHASE)
466 				return B_NOT_ALLOWED;
467 
468 			free(fUsername);
469 			fUsername = data ? strdup((const char*) data) : strdup("");
470 		} break;
471 
472 		case PPPC_SET_PASSWORD: {
473 			if(!data)
474 				return B_ERROR;
475 
476 			LockerHelper locker(fLock);
477 			// login information can only be changed before we authenticate
478 			if(Phase() >= PPP_AUTHENTICATION_PHASE)
479 				return B_NOT_ALLOWED;
480 
481 			free(fPassword);
482 			fPassword = data ? strdup((const char*) data) : strdup("");
483 		} break;
484 
485 		case PPPC_SET_ASK_BEFORE_CONNECTING:
486 			if(length < sizeof(uint32) || !data)
487 				return B_ERROR;
488 
489 			SetAskBeforeConnecting(*((uint32*)data));
490 		break;
491 
492 		case PPPC_SET_MRU:
493 			if(length < sizeof(uint32) || !data)
494 				return B_ERROR;
495 
496 			SetMRU(*((uint32*)data));
497 		break;
498 
499 		case PPPC_SET_CONNECT_ON_DEMAND:
500 			if(length < sizeof(uint32) || !data)
501 				return B_ERROR;
502 
503 			SetConnectOnDemand(*((uint32*)data));
504 		break;
505 
506 		case PPPC_SET_AUTO_RECONNECT:
507 			if(length < sizeof(uint32) || !data)
508 				return B_ERROR;
509 
510 			SetAutoReconnect(*((uint32*)data));
511 		break;
512 
513 		case PPPC_HAS_INTERFACE_SETTINGS:
514 			if(length < sizeof(driver_settings) || !data)
515 				return B_ERROR;
516 
517 			if(equal_interface_settings(Settings(), (driver_settings*) data))
518 				return B_OK;
519 			else
520 				return B_ERROR;
521 		break;
522 
523 		case PPPC_ENABLE_REPORTS: {
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 		case PPPC_DISABLE_REPORTS: {
544 			if(length < sizeof(ppp_report_request) || !data)
545 				return B_ERROR;
546 
547 			ppp_report_request *request = (ppp_report_request*) data;
548 			ReportManager().DisableReports(request->type, request->thread);
549 		} break;
550 
551 		case PPPC_GET_STATISTICS: {
552 			if(length < sizeof(ppp_statistics) || !data)
553 				return B_ERROR;
554 
555 			memcpy(data, &fStatistics, sizeof(ppp_statistics));
556 		} break;
557 
558 		case PPPC_CONTROL_DEVICE: {
559 			if(length < sizeof(ppp_control_info) || !data)
560 				return B_ERROR;
561 
562 			ppp_control_info *control = (ppp_control_info*) data;
563 			if(control->index != 0 || !Device())
564 				return B_BAD_INDEX;
565 
566 			return Device()->Control(control->op, control->data, control->length);
567 		} break;
568 
569 		case PPPC_CONTROL_PROTOCOL: {
570 			if(length < sizeof(ppp_control_info) || !data)
571 				return B_ERROR;
572 
573 			ppp_control_info *control = (ppp_control_info*) data;
574 			KPPPProtocol *protocol = ProtocolAt(control->index);
575 			if(!protocol)
576 				return B_BAD_INDEX;
577 
578 			return protocol->Control(control->op, control->data, control->length);
579 		} break;
580 
581 		case PPPC_CONTROL_OPTION_HANDLER: {
582 			if(length < sizeof(ppp_control_info) || !data)
583 				return B_ERROR;
584 
585 			ppp_control_info *control = (ppp_control_info*) data;
586 			KPPPOptionHandler *optionHandler = LCP().OptionHandlerAt(control->index);
587 			if(!optionHandler)
588 				return B_BAD_INDEX;
589 
590 			return optionHandler->Control(control->op, control->data,
591 				control->length);
592 		} break;
593 
594 		case PPPC_CONTROL_LCP_EXTENSION: {
595 			if(length < sizeof(ppp_control_info) || !data)
596 				return B_ERROR;
597 
598 			ppp_control_info *control = (ppp_control_info*) data;
599 			KPPPLCPExtension *lcpExtension = LCP().LCPExtensionAt(control->index);
600 			if(!lcpExtension)
601 				return B_BAD_INDEX;
602 
603 			return lcpExtension->Control(control->op, control->data,
604 				control->length);
605 		} break;
606 
607 		case PPPC_CONTROL_CHILD: {
608 			if(length < sizeof(ppp_control_info) || !data)
609 				return B_ERROR;
610 
611 			ppp_control_info *control = (ppp_control_info*) data;
612 			KPPPInterface *child = ChildAt(control->index);
613 			if(!child)
614 				return B_BAD_INDEX;
615 
616 			return child->Control(control->op, control->data, control->length);
617 		} break;
618 
619 		default:
620 			return B_BAD_VALUE;
621 	}
622 
623 	return B_OK;
624 }
625 
626 
627 /*!	\brief Sets a new device for this interface.
628 
629 	A device add-on should call this method to register itself. The best place to do
630 	this is in your module's \c add_to() function.
631 
632 	\param device The device object.
633 
634 	\return \c true if successful or \c false otherwise.
635 
636 	\sa KPPPDevice
637 	\sa kppp_module_info
638 */
639 bool
640 KPPPInterface::SetDevice(KPPPDevice *device)
641 {
642 	TRACE("KPPPInterface: SetDevice(%p)\n", device);
643 
644 	if(device && &device->Interface() != this)
645 		return false;
646 
647 	if(IsMultilink() && !Parent())
648 		return false;
649 			// main interfaces do not have devices
650 
651 	LockerHelper locker(fLock);
652 
653 	if(Phase() != PPP_DOWN_PHASE)
654 		return false;
655 			// a running connection may not change
656 
657 	if(fDevice && (IsUp() || fDevice->IsUp()))
658 		Down();
659 
660 	fDevice = device;
661 	SetNext(device);
662 
663 	if(fDevice)
664 		fMRU = fDevice->MTU() - 2;
665 
666 	CalculateInterfaceMTU();
667 	CalculateBaudRate();
668 
669 	return true;
670 }
671 
672 
673 /*!	\brief Adds a new protocol to this interface.
674 
675 	NOTE: You can only add protocols in \c PPP_DOWN_PHASE. \n
676 	A protocol add-on should call this method to register itself. The best place to do
677 	this is in your module's \c add_to() function.
678 
679 	\param protocol The protocol object.
680 
681 	\return \c true if successful or \c false otherwise.
682 
683 	\sa KPPPProtocol
684 	\sa kppp_module_info
685 */
686 bool
687 KPPPInterface::AddProtocol(KPPPProtocol *protocol)
688 {
689 	// Find insert position after the last protocol
690 	// with the same level.
691 
692 	TRACE("KPPPInterface: AddProtocol(%X)\n",
693 		protocol ? protocol->ProtocolNumber() : 0);
694 
695 	if(!protocol || &protocol->Interface() != this
696 			|| protocol->Level() == PPP_INTERFACE_LEVEL)
697 		return false;
698 
699 	LockerHelper locker(fLock);
700 
701 	if(Phase() != PPP_DOWN_PHASE)
702 		return false;
703 			// a running connection may not change
704 
705 	KPPPProtocol *current = fFirstProtocol, *previous = NULL;
706 
707 	while(current) {
708 		if(current->Level() < protocol->Level())
709 			break;
710 
711 		previous = current;
712 		current = current->NextProtocol();
713 	}
714 
715 	if(!current) {
716 		if(!previous)
717 			fFirstProtocol = protocol;
718 		else
719 			previous->SetNextProtocol(protocol);
720 
721 		// set up the last protocol in the chain
722 		protocol->SetNextProtocol(NULL);
723 			// this also sets next to NULL
724 		protocol->SetNext(this);
725 			// we need to set us as the next layer for the last protocol
726 	} else {
727 		protocol->SetNextProtocol(current);
728 
729 		if(!previous)
730 			fFirstProtocol = protocol;
731 		else
732 			previous->SetNextProtocol(protocol);
733 	}
734 
735 	if(protocol->Level() < PPP_PROTOCOL_LEVEL)
736 		CalculateInterfaceMTU();
737 
738 	if(IsUp() || Phase() >= protocol->ActivationPhase())
739 		protocol->Up();
740 
741 	return true;
742 }
743 
744 
745 /*!	\brief Removes a protocol from this interface.
746 
747 	NOTE: You can only remove protocols in \c PPP_DOWN_PHASE. \n
748 	A protocol add-on should call this method to remove itself explicitly from the
749 	interface. \n
750 	Normally, this method is called in KPPPProtocol's destructor. Do not call it
751 	yourself unless you know what you do!
752 
753 	\param protocol The protocol object.
754 
755 	\return \c true if successful or \c false otherwise.
756 */
757 bool
758 KPPPInterface::RemoveProtocol(KPPPProtocol *protocol)
759 {
760 	TRACE("KPPPInterface: RemoveProtocol(%X)\n",
761 		protocol ? protocol->ProtocolNumber() : 0);
762 
763 	LockerHelper locker(fLock);
764 
765 	if(Phase() != PPP_DOWN_PHASE)
766 		return false;
767 			// a running connection may not change
768 
769 	KPPPProtocol *current = fFirstProtocol, *previous = NULL;
770 
771 	while(current) {
772 		if(current == protocol) {
773 			if(!protocol->IsDown())
774 				protocol->Down();
775 
776 			if(previous) {
777 				previous->SetNextProtocol(current->NextProtocol());
778 
779 				// set us as next layer if needed
780 				if(!previous->Next())
781 					previous->SetNext(this);
782 			} else
783 				fFirstProtocol = current->NextProtocol();
784 
785 			current->SetNextProtocol(NULL);
786 
787 			CalculateInterfaceMTU();
788 
789 			return true;
790 		}
791 
792 		previous = current;
793 		current = current->NextProtocol();
794 	}
795 
796 	return false;
797 }
798 
799 
800 //!	Returns the number of protocol modules belonging to this interface.
801 int32
802 KPPPInterface::CountProtocols() const
803 {
804 	KPPPProtocol *protocol = FirstProtocol();
805 
806 	int32 count = 0;
807 	for(; protocol; protocol = protocol->NextProtocol())
808 		++count;
809 
810 	return count;
811 }
812 
813 
814 //!	Returns the protocol at the given \a index or \c NULL if it could not be found.
815 KPPPProtocol*
816 KPPPInterface::ProtocolAt(int32 index) const
817 {
818 	KPPPProtocol *protocol = FirstProtocol();
819 
820 	int32 currentIndex = 0;
821 	for(; protocol && currentIndex != index; protocol = protocol->NextProtocol())
822 		++currentIndex;
823 
824 	return protocol;
825 }
826 
827 
828 /*!	\brief Returns the protocol object responsible for a given protocol number.
829 
830 	\param protocolNumber The protocol number that the object should handle.
831 	\param start (Optional): Start with this protocol. Can be used for iteration.
832 
833 	\return Either the object that was found or \c NULL.
834 */
835 KPPPProtocol*
836 KPPPInterface::ProtocolFor(uint16 protocolNumber, KPPPProtocol *start) const
837 {
838 	TRACE("KPPPInterface: ProtocolFor(%X)\n", protocolNumber);
839 
840 	KPPPProtocol *current = start ? start : FirstProtocol();
841 
842 	for(; current; current = current->NextProtocol()) {
843 		if(current->ProtocolNumber() == protocolNumber
844 				|| (current->Flags() & PPP_INCLUDES_NCP
845 					&& (current->ProtocolNumber() & 0x7FFF)
846 						== (protocolNumber & 0x7FFF)))
847 			return current;
848 	}
849 
850 	return NULL;
851 }
852 
853 
854 //!	Adds a new child interface (used for multilink interfaces).
855 bool
856 KPPPInterface::AddChild(KPPPInterface *child)
857 {
858 	TRACE("KPPPInterface: AddChild(%lX)\n", child ? child->ID() : 0);
859 
860 	if(!child)
861 		return false;
862 
863 	LockerHelper locker(fLock);
864 
865 	if(fChildren.HasItem(child) || !fChildren.AddItem(child))
866 		return false;
867 
868 	child->SetParent(this);
869 
870 	return true;
871 }
872 
873 
874 //!	Removes a new child from this interface (used for multilink interfaces).
875 bool
876 KPPPInterface::RemoveChild(KPPPInterface *child)
877 {
878 	TRACE("KPPPInterface: RemoveChild(%lX)\n", child ? child->ID() : 0);
879 
880 	LockerHelper locker(fLock);
881 
882 	if(!fChildren.RemoveItem(child))
883 		return false;
884 
885 	child->SetParent(NULL);
886 
887 	// parents cannot exist without their children
888 	if(CountChildren() == 0 && fManager && Ifnet())
889 		Delete();
890 
891 	return true;
892 }
893 
894 
895 //!	Returns the child interface at the given \a index (used for multilink interfaces).
896 KPPPInterface*
897 KPPPInterface::ChildAt(int32 index) const
898 {
899 	TRACE("KPPPInterface: ChildAt(%ld)\n", index);
900 
901 	KPPPInterface *child = fChildren.ItemAt(index);
902 
903 	if(child == fChildren.GetDefaultItem())
904 		return NULL;
905 
906 	return child;
907 }
908 
909 
910 //!	Enables or disables the auto-reconnect feture.
911 void
912 KPPPInterface::SetAutoReconnect(bool autoReconnect)
913 {
914 	TRACE("KPPPInterface: SetAutoReconnect(%s)\n", autoReconnect ? "true" : "false");
915 
916 	if(Mode() != PPP_CLIENT_MODE)
917 		return;
918 
919 	LockerHelper locker(fLock);
920 
921 	fAutoReconnect = autoReconnect;
922 }
923 
924 
925 //!	Enables or disables the connect-on-demand feature.
926 void
927 KPPPInterface::SetConnectOnDemand(bool connectOnDemand)
928 {
929 	// All protocols must check if ConnectOnDemand was enabled/disabled after this
930 	// interface went down. This is the only situation where a change is relevant.
931 
932 	TRACE("KPPPInterface: SetConnectOnDemand(%s)\n", connectOnDemand ? "true" : "false");
933 
934 	// Only clients support ConnectOnDemand.
935 	if(Mode() != PPP_CLIENT_MODE) {
936 		TRACE("KPPPInterface::SetConnectOnDemand(): Wrong mode!\n");
937 		fConnectOnDemand = false;
938 		return;
939 	} else if(DoesConnectOnDemand() == connectOnDemand)
940 		return;
941 
942 	LockerHelper locker(fLock);
943 
944 	fConnectOnDemand = connectOnDemand;
945 
946 	// Do not allow changes when we are disconnected (only main interfaces).
947 	// This would make no sense because
948 	// - enabling: this cannot happen because hidden interfaces are deleted if they
949 	//    could not establish a connection (the user cannot access hidden interfaces)
950 	// - disabling: the interface disappears as seen from the user, so we delete it
951 	if(!Parent() && State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE) {
952 		if(!connectOnDemand)
953 			Delete();
954 				// as long as the protocols were not configured we can just delete us
955 
956 		return;
957 	}
958 
959 	// check if we need to set/unset flags
960 	if(connectOnDemand) {
961 		if(Ifnet())
962 			Ifnet()->if_flags |= IFF_UP;
963 	} else if(!connectOnDemand && Phase() < PPP_ESTABLISHED_PHASE) {
964 		if(Ifnet())
965 			Ifnet()->if_flags &= ~IFF_UP;
966 	}
967 }
968 
969 
970 //!	Sets whether the user is asked before establishing the connection.
971 void
972 KPPPInterface::SetAskBeforeConnecting(bool ask)
973 {
974 	LockerHelper locker(fLock);
975 	bool old = fAskBeforeConnecting;
976 	fAskBeforeConnecting = ask;
977 	if(old && fAskBeforeConnecting == false && State() == PPP_STARTING_STATE
978 			&& Phase() == PPP_DOWN_PHASE) {
979 		locker.UnlockNow();
980 		StateMachine().ContinueOpenEvent();
981 	}
982 }
983 
984 
985 //!	Sets Protocol-Field-Compression options.
986 bool
987 KPPPInterface::SetPFCOptions(uint8 pfcOptions)
988 {
989 	TRACE("KPPPInterface: SetPFCOptions(0x%X)\n", pfcOptions);
990 
991 	if(PFCOptions() & PPP_FREEZE_PFC_OPTIONS)
992 		return false;
993 
994 	fPFCOptions = pfcOptions;
995 	return true;
996 }
997 
998 
999 /*!	\brief Brings this interface up.
1000 
1001 	\c Down() overrides all \c Up() requests. \n
1002 	This method runs an asynchronous process (it returns immediately).
1003 
1004 	\return \c false on error.
1005 */
1006 bool
1007 KPPPInterface::Up()
1008 {
1009 	TRACE("KPPPInterface: Up()\n");
1010 
1011 	if(InitCheck() != B_OK || Phase() == PPP_TERMINATION_PHASE)
1012 		return false;
1013 
1014 	if(IsUp())
1015 		return true;
1016 
1017 	// Lock needs timeout because destructor could have locked the interface.
1018 	while(fLock.LockWithTimeout(100000) != B_NO_ERROR)
1019 		if(fDeleteCounter > 0)
1020 			return false;
1021 
1022 	StateMachine().OpenEvent();
1023 	fLock.Unlock();
1024 
1025 	return true;
1026 }
1027 
1028 
1029 /*!	\brief Brings this interface down.
1030 
1031 	\c Down() overrides all \c Up() requests. \n
1032 	This method runs an asynchronous process (it returns immediately).
1033 
1034 	\return \c false on error.
1035 */
1036 bool
1037 KPPPInterface::Down()
1038 {
1039 	TRACE("KPPPInterface: Down()\n");
1040 
1041 	if(InitCheck() != B_OK)
1042 		return false;
1043 	else if(State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE)
1044 		return true;
1045 
1046 	send_data_with_timeout(fReconnectThread, 0, NULL, 0, 200);
1047 		// tell the reconnect thread to abort its attempt (if it's still waiting)
1048 	StateMachine().CloseEvent();
1049 
1050 	return true;
1051 }
1052 
1053 
1054 //!	Waits for connection establishment. Returns true if successful.
1055 bool
1056 KPPPInterface::WaitForConnection()
1057 {
1058 	TRACE("KPPPInterface: WaitForConnection()\n");
1059 
1060 	if(InitCheck() != B_OK)
1061 		return false;
1062 
1063 	// Lock needs timeout because destructor could have locked the interface.
1064 	while(fLock.LockWithTimeout(100000) != B_NO_ERROR)
1065 		if(fDeleteCounter > 0)
1066 			return false;
1067 
1068 	ReportManager().EnableReports(PPP_CONNECTION_REPORT, find_thread(NULL));
1069 	fLock.Unlock();
1070 
1071 	ppp_report_packet report;
1072 	thread_id sender;
1073 	bool successful = false;
1074 	while(true) {
1075 		if(receive_data(&sender, &report, sizeof(report)) != PPP_REPORT_CODE)
1076 			continue;
1077 
1078 		if(report.type == PPP_DESTRUCTION_REPORT)
1079 			break;
1080 		else if(report.type != PPP_CONNECTION_REPORT)
1081 			continue;
1082 
1083 		if(report.code == PPP_REPORT_UP_SUCCESSFUL) {
1084 			successful = true;
1085 			break;
1086 		} else if(report.code == PPP_REPORT_DOWN_SUCCESSFUL)
1087 			break;
1088 	}
1089 
1090 	ReportManager().DisableReports(PPP_CONNECTION_REPORT, find_thread(NULL));
1091 	return successful;
1092 }
1093 
1094 
1095 //!	Returns if the interface is connected.
1096 bool
1097 KPPPInterface::IsUp() const
1098 {
1099 	LockerHelper locker(fLock);
1100 	return Phase() == PPP_ESTABLISHED_PHASE;
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.
1225 
1226 	\param packet The packet.
1227 	\param protocolNumber The packet's protocol number.
1228 
1229 	\return
1230 		- \c B_OK: Sending was successful.
1231 		- \c B_ERROR: Some error occured.
1232 */
1233 status_t
1234 KPPPInterface::Send(struct mbuf *packet, uint16 protocolNumber)
1235 {
1236 	TRACE("KPPPInterface: Send(0x%X)\n", protocolNumber);
1237 
1238 	if(!packet)
1239 		return B_ERROR;
1240 
1241 	// we must pass the basic tests like:
1242 	// do we have a device?
1243 	// did we load all modules?
1244 	if(InitCheck() != B_OK) {
1245 		m_freem(packet);
1246 		return B_ERROR;
1247 	}
1248 
1249 	// go up if ConnectOnDemand is enabled and we are disconnected
1250 	if((protocolNumber != PPP_LCP_PROTOCOL && DoesConnectOnDemand()
1251 			&& (Phase() == PPP_DOWN_PHASE
1252 				|| Phase() == PPP_ESTABLISHMENT_PHASE)
1253 			&& !Up()) || !WaitForConnection()) {
1254 		m_freem(packet);
1255 		return B_ERROR;
1256 	}
1257 
1258 	// find the protocol handler for the current protocol number
1259 	KPPPProtocol *protocol = ProtocolFor(protocolNumber);
1260 	while(protocol && !protocol->IsEnabled())
1261 		protocol = protocol->NextProtocol() ?
1262 			ProtocolFor(protocolNumber, protocol->NextProtocol()) : NULL;
1263 
1264 #if DEBUG
1265 	if(!protocol)
1266 		TRACE("KPPPInterface::Send(): no protocol found!\n");
1267 	else if(!Device()->IsUp())
1268 		TRACE("KPPPInterface::Send(): device is not up!\n");
1269 	else if(!protocol->IsEnabled())
1270 		TRACE("KPPPInterface::Send(): protocol not enabled!\n");
1271 	else if(!IsProtocolAllowed(*protocol))
1272 		TRACE("KPPPInterface::Send(): protocol not allowed to send!\n");
1273 	else
1274 		TRACE("KPPPInterface::Send(): protocol allowed\n");
1275 #endif
1276 
1277 	// make sure that protocol is allowed to send and everything is up
1278 	if(!Device()->IsUp() || !protocol || !protocol->IsEnabled()
1279 			|| !IsProtocolAllowed(*protocol)) {
1280 		ERROR("KPPPInterface::Send(): cannot send!\n");
1281 		m_freem(packet);
1282 		return B_ERROR;
1283 	}
1284 
1285 	// encode in ppp frame and consider using PFC
1286 	if(UseLocalPFC() && protocolNumber & 0xFF00 == 0) {
1287 		M_PREPEND(packet, 1);
1288 
1289 		if(packet == NULL)
1290 			return B_ERROR;
1291 
1292 		uint8 *header = mtod(packet, uint8*);
1293 		*header = protocolNumber & 0xFF;
1294 	} else {
1295 		M_PREPEND(packet, 2);
1296 
1297 		if(packet == NULL)
1298 			return B_ERROR;
1299 
1300 		// set protocol (the only header field)
1301 		protocolNumber = htons(protocolNumber);
1302 		uint16 *header = mtod(packet, uint16*);
1303 		*header = protocolNumber;
1304 	}
1305 
1306 	// pass to device/children
1307 	if(!IsMultilink() || Parent()) {
1308 		// check if packet is too big for device
1309 		uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len :
1310 			packet->m_len;
1311 
1312 		if(length > MRU()) {
1313 			m_freem(packet);
1314 			return B_ERROR;
1315 		}
1316 
1317 		atomic_add64(&fStatistics.bytesSent, length);
1318 		atomic_add64(&fStatistics.packetsSent, 1);
1319 		return SendToNext(packet, 0);
1320 			// this is normally the device, but there can be something inbetween
1321 	} else {
1322 		// the multilink protocol should have sent it to some child interface
1323 		m_freem(packet);
1324 		return B_ERROR;
1325 	}
1326 }
1327 
1328 
1329 /*!	\brief Receives a packet.
1330 
1331 	Encapsulation protocols may use this method to pass encapsulated packets to the
1332 	PPP interface. Packets will be handled as if they were raw packets that came
1333 	directly from the device via \c ReceiveFromDevice(). \n
1334 	If no handler could be found in this interface the parent's \c Receive() method
1335 	is called.
1336 
1337 	\param packet The packet.
1338 	\param protocolNumber The packet's protocol number.
1339 
1340 	\return
1341 		- \c B_OK: Receiving was successful.
1342 		- \c B_ERROR: Some error occured.
1343 		- \c PPP_REJECTED: No protocol handler could be found for this packet.
1344 		- \c PPP_DISCARDED: The protocol handler(s) did not handle this packet.
1345 */
1346 status_t
1347 KPPPInterface::Receive(struct mbuf *packet, uint16 protocolNumber)
1348 {
1349 	TRACE("KPPPInterface: Receive(0x%X)\n", protocolNumber);
1350 
1351 	if(!packet)
1352 		return B_ERROR;
1353 
1354 	int32 result = PPP_REJECTED;
1355 		// assume we have no handler
1356 
1357 	// Set our interface as the receiver.
1358 	// The real netstack protocols (IP, IPX, etc.) might get confused if our
1359 	// interface is a main interface and at the same time not registered
1360 	// because then there is no receiver interface.
1361 	// PPP NCPs should be aware of that!
1362 	if(packet->m_flags & M_PKTHDR && Ifnet() != NULL)
1363 		packet->m_pkthdr.rcvif = Ifnet();
1364 
1365 	// Find handler and let it parse the packet.
1366 	// The handler does need not be up because if we are a server
1367 	// the handler might be upped by this packet.
1368 	// If authenticating we only allow authentication phase protocols.
1369 	KPPPProtocol *protocol = ProtocolFor(protocolNumber);
1370 	for(; protocol;
1371 			protocol = protocol->NextProtocol() ?
1372 				ProtocolFor(protocolNumber, protocol->NextProtocol()) : NULL) {
1373 		TRACE("KPPPInterface::Receive(): trying protocol\n");
1374 
1375 		if(!protocol->IsEnabled() || !IsProtocolAllowed(*protocol))
1376 			continue;
1377 				// skip handler if disabled or not allowed
1378 
1379 		result = protocol->Receive(packet, protocolNumber);
1380 		if(result == PPP_UNHANDLED)
1381 			continue;
1382 
1383 		return result;
1384 	}
1385 
1386 	TRACE("KPPPInterface::Receive(): trying parent\n");
1387 
1388 	// maybe the parent interface can handle the packet
1389 	if(Parent())
1390 		return Parent()->Receive(packet, protocolNumber);
1391 
1392 	if(result == PPP_UNHANDLED) {
1393 		m_freem(packet);
1394 		return PPP_DISCARDED;
1395 	} else {
1396 		StateMachine().RUCEvent(packet, protocolNumber);
1397 		return PPP_REJECTED;
1398 	}
1399 }
1400 
1401 
1402 /*!	\brief Receives a base PPP packet from the device.
1403 
1404 	KPPPDevice should call this method when it receives a packet. \n
1405 	PFC decoding is handled here.
1406 
1407 	\param packet The packet.
1408 
1409 	\return
1410 		- \c B_OK: Receiving was successful.
1411 		- \c B_ERROR: Some error occured.
1412 		- \c PPP_REJECTED: No protocol handler could be found for this packet.
1413 		- \c PPP_DISCARDED: The protocol handler(s) did not handle this packet.
1414 */
1415 status_t
1416 KPPPInterface::ReceiveFromDevice(struct mbuf *packet)
1417 {
1418 	TRACE("KPPPInterface: ReceiveFromDevice()\n");
1419 
1420 	if(!packet)
1421 		return B_ERROR;
1422 
1423 	if(InitCheck() != B_OK) {
1424 		m_freem(packet);
1425 		return B_ERROR;
1426 	}
1427 
1428 	uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len :
1429 		packet->m_len;
1430 
1431 	// decode ppp frame and recognize PFC
1432 	uint16 protocolNumber = *mtod(packet, uint8*);
1433 	if(protocolNumber & 1) {
1434 		m_adj(packet, 1);
1435 	} else {
1436 		protocolNumber = ntohs(*mtod(packet, uint16*));
1437 		m_adj(packet, 2);
1438 	}
1439 
1440 	atomic_add64(&fStatistics.bytesReceived, length);
1441 	atomic_add64(&fStatistics.packetsReceived, 1);
1442 	return Receive(packet, protocolNumber);
1443 }
1444 
1445 
1446 //!	Manages Pulse() calls for all add-ons and hanldes idle-disconnection.
1447 void
1448 KPPPInterface::Pulse()
1449 {
1450 	if(Device())
1451 		Device()->Pulse();
1452 
1453 	KPPPProtocol *protocol = FirstProtocol();
1454 	for(; protocol; protocol = protocol->NextProtocol())
1455 		protocol->Pulse();
1456 
1457 	uint32 currentTime = real_time_clock();
1458 	if(fUpdateIdleSince) {
1459 		fIdleSince = currentTime;
1460 		fUpdateIdleSince = false;
1461 	}
1462 
1463 	// check our idle time and disconnect if needed
1464 	if(fDisconnectAfterIdleSince > 0 && fIdleSince != 0
1465 			&& fIdleSince - currentTime >= fDisconnectAfterIdleSince)
1466 		StateMachine().CloseEvent();
1467 }
1468 
1469 
1470 //!	Registers an ifnet structure for this interface.
1471 bool
1472 KPPPInterface::RegisterInterface()
1473 {
1474 	TRACE("KPPPInterface: RegisterInterface()\n");
1475 
1476 	if(fIfnet)
1477 		return true;
1478 			// we are already registered
1479 
1480 	LockerHelper locker(fLock);
1481 
1482 	// only MainInterfaces get an ifnet
1483 	if(IsMultilink() && Parent() && Parent()->RegisterInterface())
1484 		return true;
1485 
1486 	if(!fManager)
1487 		return false;
1488 
1489 	fIfnet = fManager->RegisterInterface(ID());
1490 
1491 	if(!fIfnet)
1492 		return false;
1493 
1494 	if(DoesConnectOnDemand())
1495 		fIfnet->if_flags |= IFF_UP;
1496 
1497 	CalculateInterfaceMTU();
1498 	CalculateBaudRate();
1499 
1500 	return true;
1501 }
1502 
1503 
1504 //!	Unregisters this interface's ifnet structure.
1505 bool
1506 KPPPInterface::UnregisterInterface()
1507 {
1508 	TRACE("KPPPInterface: UnregisterInterface()\n");
1509 
1510 	if(!fIfnet)
1511 		return true;
1512 			// we are already unregistered
1513 
1514 	LockerHelper locker(fLock);
1515 
1516 	// only MainInterfaces get an ifnet
1517 	if(IsMultilink() && Parent())
1518 		return true;
1519 
1520 	if(!fManager)
1521 		return false;
1522 
1523 	fManager->UnregisterInterface(ID());
1524 		// this will delete fIfnet, so do not access it anymore!
1525 	fIfnet = NULL;
1526 
1527 	return true;
1528 }
1529 
1530 
1531 //!	Called by KPPPManager: manager routes stack ioctls to the corresponding interface.
1532 status_t
1533 KPPPInterface::StackControl(uint32 op, void *data)
1534 {
1535 	TRACE("KPPPInterface: StackControl(0x%lX)\n", op);
1536 
1537 	switch(op) {
1538 		default:
1539 			return StackControlEachHandler(op, data);
1540 	}
1541 
1542 	return B_OK;
1543 }
1544 
1545 
1546 //!	Utility class used by ControlEachHandler().
1547 template<class T>
1548 class CallStackControl {
1549 	public:
1550 		inline CallStackControl(uint32 op, void *data, status_t& result)
1551 			: fOp(op), fData(data), fResult(result) {}
1552 		inline void operator() (T *item)
1553 			{
1554 				if(!item || !item->IsEnabled())
1555 					return;
1556 				status_t tmp = item->StackControl(fOp, fData);
1557 				if(tmp == B_OK && fResult == B_BAD_VALUE)
1558 					fResult = B_OK;
1559 				else if(tmp != B_BAD_VALUE)
1560 					fResult = tmp;
1561 			}
1562 	private:
1563 		uint32 fOp;
1564 		void *fData;
1565 		status_t& fResult;
1566 };
1567 
1568 /*!	\brief This calls Control() with the given parameters for each add-on.
1569 
1570 	\return
1571 		- \c B_OK: All handlers returned B_OK.
1572 		- \c B_BAD_VALUE: No handler was found.
1573 		- Any other value: Error code which was returned by the last failing handler.
1574 */
1575 status_t
1576 KPPPInterface::StackControlEachHandler(uint32 op, void *data)
1577 {
1578 	TRACE("KPPPInterface: StackControlEachHandler(0x%lX)\n", op);
1579 
1580 	status_t result = B_BAD_VALUE, tmp;
1581 
1582 	KPPPProtocol *protocol = FirstProtocol();
1583 	for(; protocol; protocol = protocol->NextProtocol()) {
1584 		tmp = protocol->StackControl(op, data);
1585 		if(tmp == B_OK && result == B_BAD_VALUE)
1586 			result = B_OK;
1587 		else if(tmp != B_BAD_VALUE)
1588 			result = tmp;
1589 	}
1590 
1591 	ForEachItem(LCP().fLCPExtensions,
1592 		CallStackControl<KPPPLCPExtension>(op, data, result));
1593 	ForEachItem(LCP().fOptionHandlers,
1594 		CallStackControl<KPPPOptionHandler>(op, data, result));
1595 
1596 	return result;
1597 }
1598 
1599 
1600 //!	Recalculates the MTU from the MRU (includes encapsulation protocol overheads).
1601 void
1602 KPPPInterface::CalculateInterfaceMTU()
1603 {
1604 	TRACE("KPPPInterface: CalculateInterfaceMTU()\n");
1605 
1606 	fInterfaceMTU = fMRU;
1607 	fHeaderLength = 2;
1608 
1609 	// sum all headers (the protocol field is not counted)
1610 	KPPPProtocol *protocol = FirstProtocol();
1611 	for(; protocol; protocol = protocol->NextProtocol()) {
1612 		if(protocol->Level() < PPP_PROTOCOL_LEVEL)
1613 			fHeaderLength += protocol->Overhead();
1614 	}
1615 
1616 	fInterfaceMTU -= fHeaderLength;
1617 
1618 	if(Ifnet()) {
1619 		Ifnet()->if_mtu = fInterfaceMTU;
1620 		Ifnet()->if_hdrlen = fHeaderLength;
1621 	}
1622 
1623 	if(Parent())
1624 		Parent()->CalculateInterfaceMTU();
1625 }
1626 
1627 
1628 //!	Recalculates the baud rate.
1629 void
1630 KPPPInterface::CalculateBaudRate()
1631 {
1632 	TRACE("KPPPInterface: CalculateBaudRate()\n");
1633 
1634 	if(!Ifnet())
1635 		return;
1636 
1637 	if(Device())
1638 		fIfnet->if_baudrate = max_c(Device()->InputTransferRate(),
1639 			Device()->OutputTransferRate());
1640 	else {
1641 		fIfnet->if_baudrate = 0;
1642 		for(int32 index = 0; index < CountChildren(); index++)
1643 			if(ChildAt(index)->Ifnet())
1644 				fIfnet->if_baudrate += ChildAt(index)->Ifnet()->if_baudrate;
1645 	}
1646 }
1647 
1648 
1649 //!	Reconnects. Waits a given delay (in miliseconds) before reconnecting.
1650 void
1651 KPPPInterface::Reconnect(uint32 delay)
1652 {
1653 	TRACE("KPPPInterface: Reconnect(%ld)\n", delay);
1654 
1655 	if(fReconnectThread != -1)
1656 		return;
1657 
1658 	++fConnectAttempt;
1659 
1660 	// start a new thread that calls our Up() method
1661 	reconnect_info info;
1662 	info.interface = this;
1663 	info.thread = &fReconnectThread;
1664 	info.delay = delay;
1665 
1666 	fReconnectThread = spawn_kernel_thread(reconnect_thread,
1667 		"KPPPInterface: reconnect_thread", B_NORMAL_PRIORITY, NULL);
1668 
1669 	resume_thread(fReconnectThread);
1670 
1671 	send_data(fReconnectThread, 0, &info, sizeof(reconnect_info));
1672 }
1673 
1674 
1675 status_t
1676 reconnect_thread(void *data)
1677 {
1678 	reconnect_info info;
1679 	thread_id sender;
1680 	int32 code;
1681 
1682 	receive_data(&sender, &info, sizeof(reconnect_info));
1683 
1684 	// we try to receive data instead of snooze, so we can quit on destruction
1685 	if(receive_data_with_timeout(&sender, &code, NULL, 0, info.delay) == B_OK) {
1686 		*info.thread = -1;
1687 		return B_OK;
1688 	}
1689 
1690 	info.interface->Up();
1691 	*info.thread = -1;
1692 
1693 	return B_OK;
1694 }
1695 
1696 
1697 // ----------------------------------
1698 // Function: interface_deleter_thread
1699 // ----------------------------------
1700 //!	Private class.
1701 class KPPPInterfaceAccess {
1702 	public:
1703 		KPPPInterfaceAccess() {}
1704 
1705 		void Delete(KPPPInterface *interface)
1706 			{ delete interface; }
1707 };
1708 
1709 
1710 status_t
1711 interface_deleter_thread(void *data)
1712 {
1713 	KPPPInterfaceAccess access;
1714 	access.Delete((KPPPInterface*) data);
1715 
1716 	return B_OK;
1717 }
1718