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