xref: /haiku/src/add-ons/kernel/network/ppp/ipcp/Protocol.cpp (revision 9eb55bc1d104b8fda80898f8b25c94d8000c8255)
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 #include "Protocol.h"
9 #include <KPPPConfigurePacket.h>
10 #include <KPPPInterface.h>
11 #include <settings_tools.h>
12 
13 #include <LockerHelper.h>
14 
15 #include <cstring>
16 #include <netinet/in_var.h>
17 #include <core_funcs.h>
18 #include <sys/sockio.h>
19 
20 
21 #define PPP_STATE_MACHINE_TIMEOUT			3000000
22 	// 3 seconds
23 
24 
25 IPCP::IPCP(KPPPInterface& interface, driver_parameter *settings)
26 	: KPPPProtocol("IPCP", PPP_NCP_PHASE, IPCP_PROTOCOL, PPP_PROTOCOL_LEVEL,
27 		AF_INET, 0, interface, settings, PPP_INCLUDES_NCP),
28 	fDefaultRoute(NULL),
29 	fRequestPrimaryDNS(false),
30 	fRequestSecondaryDNS(false),
31 	fState(PPP_INITIAL_STATE),
32 	fID(system_time() & 0xFF),
33 	fMaxRequest(10),
34 	fMaxTerminate(2),
35 	fMaxNak(5),
36 	fRequestID(0),
37 	fTerminateID(0),
38 	fNextTimeout(0)
39 {
40 	// reset configurations
41 	memset(&fLocalConfiguration, 0, sizeof(ipcp_configuration));
42 	memset(&fPeerConfiguration, 0, sizeof(ipcp_configuration));
43 
44 	// reset requests
45 	memset(&fLocalRequests, 0, sizeof(ipcp_requests));
46 	memset(&fPeerRequests, 0, sizeof(ipcp_requests));
47 
48 	// Parse settings:
49 	// "Local" and "Peer" describe each side's settings
50 	const driver_parameter *profile
51 		= Interface().Profile().SettingsFor("protocol", "ipcp");
52 	ParseSideRequests(get_parameter_with_name("Local", profile), PPP_LOCAL_SIDE);
53 	ParseSideRequests(get_parameter_with_name("Peer", profile), PPP_PEER_SIDE);
54 }
55 
56 
57 IPCP::~IPCP()
58 {
59 	RemoveRoutes();
60 }
61 
62 
63 status_t
64 IPCP::StackControl(uint32 op, void *data)
65 {
66 #if DEBUG
67 	dprintf("IPCP: StackControl(op=%ld)\n", op);
68 #endif
69 
70 	// TODO:
71 	// check values
72 
73 	switch(op) {
74 		case SIOCSIFADDR:
75 		break;
76 
77 		case SIOCSIFFLAGS:
78 		break;
79 
80 		case SIOCSIFDSTADDR:
81 		break;
82 
83 		case SIOCSIFNETMASK:
84 		break;
85 
86 		default:
87 			dprintf("IPCP: Unknown ioctl: %ld\n", op);
88 			return KPPPProtocol::StackControl(op, data);
89 	}
90 
91 	return B_OK;
92 }
93 
94 
95 bool
96 IPCP::Up()
97 {
98 #if DEBUG
99 	dprintf("IPCP: Up() state=%d\n", State());
100 #endif
101 
102 	// Servers do not send a configure-request when Up() is called. They wait until
103 	// the client requests this protocol.
104 	if(Interface().Mode() == PPP_SERVER_MODE)
105 		return true;
106 
107 	LockerHelper locker(fLock);
108 
109 	switch(State()) {
110 		case PPP_INITIAL_STATE:
111 			NewState(PPP_REQ_SENT_STATE);
112 			InitializeRestartCount();
113 			locker.UnlockNow();
114 			SendConfigureRequest();
115 		break;
116 
117 		default:
118 			;
119 	}
120 
121 	return true;
122 }
123 
124 
125 bool
126 IPCP::Down()
127 {
128 #if DEBUG
129 	dprintf("IPCP: Down() state=%d\n", State());
130 #endif
131 
132 	LockerHelper locker(fLock);
133 
134 	switch(Interface().Phase()) {
135 		case PPP_DOWN_PHASE:
136 			// interface finished terminating
137 			NewState(PPP_INITIAL_STATE);
138 			locker.UnlockNow();
139 			ReportDownEvent();
140 				// this will also reset and update addresses
141 		break;
142 
143 /*		case PPP_TERMINATION_PHASE:
144 			// interface is terminating
145 		break;
146 
147 		case PPP_ESTABLISHMENT_PHASE:
148 			// interface is reconfiguring
149 		break;
150 */
151 		case PPP_ESTABLISHED_PHASE:
152 			// terminate this NCP individually (block until we finished terminating)
153 			if(State() != PPP_INITIAL_STATE && State() != PPP_CLOSING_STATE) {
154 				NewState(PPP_CLOSING_STATE);
155 				InitializeRestartCount();
156 				locker.UnlockNow();
157 				SendTerminateRequest();
158 			}
159 
160 			while(State() == PPP_CLOSING_STATE)
161 				snooze(50000);
162 		break;
163 
164 		default:
165 			;
166 	}
167 
168 	return true;
169 }
170 
171 
172 status_t
173 IPCP::Send(struct mbuf *packet, uint16 protocolNumber = IPCP_PROTOCOL)
174 {
175 #if DEBUG
176 	dprintf("IPCP: Send(0x%X)\n", protocolNumber);
177 #endif
178 
179 	if((protocolNumber == IP_PROTOCOL && State() == PPP_OPENED_STATE)
180 			|| protocolNumber == IPCP_PROTOCOL)
181 		return SendToNext(packet, protocolNumber);
182 
183 	dprintf("IPCP: Send() failed because of wrong state or protocol number!\n");
184 
185 	m_freem(packet);
186 	return B_ERROR;
187 }
188 
189 
190 status_t
191 IPCP::Receive(struct mbuf *packet, uint16 protocolNumber)
192 {
193 #if DEBUG
194 	dprintf("IPCP: Receive(0x%X)\n", protocolNumber);
195 #endif
196 
197 	if(!packet)
198 		return B_ERROR;
199 
200 	if(protocolNumber == IP_PROTOCOL)
201 		return ReceiveIPPacket(packet, protocolNumber);
202 
203 	if(protocolNumber != IPCP_PROTOCOL)
204 		return PPP_UNHANDLED;
205 
206 	ppp_lcp_packet *data = mtod(packet, ppp_lcp_packet*);
207 
208 	// remove padding
209 	int32 length = packet->m_len;
210 	if(packet->m_flags & M_PKTHDR)
211 		length = packet->m_pkthdr.len;
212 	length -= ntohs(data->length);
213 	if(length)
214 		m_adj(packet, -length);
215 
216 	if(ntohs(data->length) < 4)
217 		return B_ERROR;
218 
219 	// packet is freed by event methods
220 	switch(data->code) {
221 		case PPP_CONFIGURE_REQUEST:
222 			RCREvent(packet);
223 		break;
224 
225 		case PPP_CONFIGURE_ACK:
226 			RCAEvent(packet);
227 		break;
228 
229 		case PPP_CONFIGURE_NAK:
230 		case PPP_CONFIGURE_REJECT:
231 			RCNEvent(packet);
232 		break;
233 
234 		case PPP_TERMINATE_REQUEST:
235 			RTREvent(packet);
236 		break;
237 
238 		case PPP_TERMINATE_ACK:
239 			RTAEvent(packet);
240 		break;
241 
242 		case PPP_CODE_REJECT:
243 			RXJBadEvent(packet);
244 				// we implemented the minimum requirements
245 		break;
246 
247 		default:
248 			RUCEvent(packet);
249 			return PPP_REJECTED;
250 	}
251 
252 	return B_OK;
253 }
254 
255 
256 status_t
257 IPCP::ReceiveIPPacket(struct mbuf *packet, uint16 protocolNumber)
258 {
259 	if(protocolNumber != IP_PROTOCOL || State() != PPP_OPENED_STATE)
260 		return PPP_UNHANDLED;
261 
262 	// TODO: add VJC support (the packet would be decoded here)
263 
264 	if (gProto[IPPROTO_IP] && gProto[IPPROTO_IP]->pr_input) {
265 		gProto[IPPROTO_IP]->pr_input(packet, 0);
266 		return B_OK;
267 	} else {
268 		dprintf("IPCP: Error: Could not find input function for IP!\n");
269 		m_freem(packet);
270 		return B_ERROR;
271 	}
272 }
273 
274 
275 void
276 IPCP::Pulse()
277 {
278 	LockerHelper locker(fLock);
279 	if(fNextTimeout == 0 || fNextTimeout > system_time())
280 		return;
281 	fNextTimeout = 0;
282 	locker.UnlockNow();
283 
284 	switch(State()) {
285 		case PPP_CLOSING_STATE:
286 			if(fTerminateCounter <= 0)
287 				TOBadEvent();
288 			else
289 				TOGoodEvent();
290 		break;
291 
292 		case PPP_REQ_SENT_STATE:
293 		case PPP_ACK_RCVD_STATE:
294 		case PPP_ACK_SENT_STATE:
295 			if(fRequestCounter <= 0)
296 				TOBadEvent();
297 			else
298 				TOGoodEvent();
299 		break;
300 
301 		default:
302 			;
303 	}
304 }
305 
306 
307 bool
308 IPCP::ParseSideRequests(const driver_parameter *requests, ppp_side side)
309 {
310 	if(!requests)
311 		return false;
312 
313 	ipcp_requests *selectedRequests;
314 
315 	if(side == PPP_LOCAL_SIDE) {
316 		selectedRequests = &fLocalRequests;
317 		fRequestPrimaryDNS = fRequestSecondaryDNS = false;
318 	} else
319 		selectedRequests = &fPeerRequests;
320 
321 	memset(selectedRequests, 0, sizeof(ipcp_requests));
322 		// reset current requests
323 
324 	// The following values are allowed:
325 	//  "Address"		the ip address that will be suggested
326 	//  "Netmask"		the netmask that should be used
327 	//  "PrimaryDNS"	primary DNS server
328 	//  "SecondaryDNS"	secondary DNS server
329 	// Setting any value to 0.0.0.0 or "auto" means it should be chosen automatically.
330 
331 	in_addr_t address = INADDR_ANY;
332 	for(int32 index = 0; index < requests->parameter_count; index++) {
333 		if(requests->parameters[index].value_count == 0)
334 			continue;
335 
336 		// all values are IP addresses, so parse the address here
337 		if(strcasecmp(requests->parameters[index].values[0], "auto")) {
338 			address = inet_addr(requests->parameters[index].values[0]);
339 			if(address == INADDR_NONE)
340 				continue;
341 		}
342 
343 		if(!strcasecmp(requests->parameters[index].name, "Address"))
344 			selectedRequests->address = address;
345 		else if(!strcasecmp(requests->parameters[index].name, "Netmask"))
346 			selectedRequests->netmask = address;
347 		else if(!strcasecmp(requests->parameters[index].name, "PrimaryDNS")) {
348 			selectedRequests->primaryDNS = address;
349 			if(side == PPP_LOCAL_SIDE)
350 				fRequestPrimaryDNS = true;
351 		} else if(!strcasecmp(requests->parameters[index].name, "SecondaryDNS")) {
352 			selectedRequests->secondaryDNS = address;
353 			if(side == PPP_LOCAL_SIDE)
354 				fRequestSecondaryDNS = true;
355 		}
356 	}
357 
358 	return true;
359 }
360 
361 
362 void
363 IPCP::UpdateAddresses()
364 {
365 	RemoveRoutes();
366 
367 	if(State() != PPP_OPENED_STATE && !Interface().DoesDialOnDemand())
368 		return;
369 
370 	struct in_aliasreq inreq;
371 	struct ifreq ifreqAddress, ifreqDestination;
372 	memset(&inreq, 0, sizeof(struct in_aliasreq));
373 	memset(&ifreqAddress, 0, sizeof(struct ifreq));
374 	memset(&ifreqDestination, 0, sizeof(struct ifreq));
375 	memset(&fGateway, 0, sizeof(struct sockaddr_in));
376 
377 	// create local address
378 	inreq.ifra_addr.sin_family = AF_INET;
379 	if(fLocalRequests.address != INADDR_ANY)
380 		inreq.ifra_addr.sin_addr.s_addr = fLocalRequests.address;
381 	else if(fLocalConfiguration.address == INADDR_ANY)
382 		inreq.ifra_addr.sin_addr.s_addr = INADDR_BROADCAST;
383 	else
384 		inreq.ifra_addr.sin_addr.s_addr = fLocalConfiguration.address;
385 	inreq.ifra_addr.sin_len = sizeof(struct sockaddr_in);
386 	memcpy(&ifreqAddress.ifr_addr, &inreq.ifra_addr, sizeof(struct sockaddr_in));
387 
388 	// create destination address
389 	fGateway.sin_family = AF_INET;
390 	if(fPeerRequests.address != INADDR_ANY)
391 		fGateway.sin_addr.s_addr = fPeerRequests.address;
392 	else if(fPeerConfiguration.address == INADDR_ANY)
393 		fGateway.sin_addr.s_addr = INADDR_BROADCAST;
394 	else
395 		fGateway.sin_addr.s_addr = fPeerConfiguration.address;
396 	fGateway.sin_len = sizeof(struct sockaddr_in);
397 	memcpy(&inreq.ifra_dstaddr, &fGateway,
398 		sizeof(struct sockaddr_in));
399 	memcpy(&ifreqDestination.ifr_dstaddr, &inreq.ifra_dstaddr,
400 		sizeof(struct sockaddr_in));
401 
402 	// create netmask
403 	inreq.ifra_mask.sin_family = AF_INET;
404 	inreq.ifra_mask.sin_addr.s_addr = fLocalRequests.netmask;
405 	inreq.ifra_mask.sin_len = sizeof(struct sockaddr_in);
406 
407 	// tell stack to use these values
408 	if(in_control(NULL, SIOCAIFADDR, (caddr_t) &inreq,
409 			Interface().Ifnet()) != B_OK)
410 		dprintf("IPCP: UpdateAddress(): SIOCAIFADDR returned error!\n");
411 	if(in_control(NULL, SIOCSIFADDR, (caddr_t) &ifreqAddress,
412 			Interface().Ifnet()) != B_OK)
413 		dprintf("IPCP: UpdateAddress(): SIOCSIFADDR returned error!\n");
414 	if(in_control(NULL, SIOCSIFDSTADDR, (caddr_t) &ifreqDestination,
415 			Interface().Ifnet()) != B_OK)
416 		dprintf("IPCP: UpdateAddress(): SIOCSIFDSTADDR returned error!\n");
417 	memcpy(&inreq.ifra_addr, &inreq.ifra_mask, sizeof(struct sockaddr_in));
418 		// SIOCISFNETMASK wants the netmask to be in ifra_addr
419 	if(in_control(NULL, SIOCSIFNETMASK, (caddr_t) &inreq,
420 			Interface().Ifnet()) != B_OK)
421 		dprintf("IPCP: UpdateAddress(): SIOCSIFNETMASK returned error!\n");
422 
423 	// add default/subnet route
424 	if(Side() == PPP_LOCAL_SIDE) {
425 		if(rtrequest(RTM_ADD, (struct sockaddr*) &inreq.ifra_mask,
426 				(struct sockaddr*) &fGateway, (struct sockaddr*) &inreq.ifra_mask,
427 				RTF_UP | RTF_GATEWAY, &fDefaultRoute) != B_OK)
428 			dprintf("IPCP: UpdateAddress(): could not add default/subnet route!\n");
429 
430 		--fDefaultRoute->rt_refcnt;
431 	}
432 }
433 
434 
435 void
436 IPCP::RemoveRoutes()
437 {
438 	// note: netstack creates and deletes destination route automatically
439 
440 	if(fDefaultRoute) {
441 		struct sockaddr_in netmask;
442 		memset(&netmask, 0, sizeof(struct sockaddr_in));
443 
444 		netmask.sin_family = AF_INET;
445 		netmask.sin_addr.s_addr = fLocalRequests.netmask;
446 		netmask.sin_len = sizeof(struct sockaddr_in);
447 
448 		if(rtrequest(RTM_DELETE, (struct sockaddr*) &netmask,
449 				(struct sockaddr*) &fGateway, (struct sockaddr*) &netmask,
450 				RTF_GATEWAY, &fDefaultRoute) != B_OK)
451 			dprintf("IPCP: RemoveRoutes(): could not remove default/subnet route!\n");
452 
453 		fDefaultRoute = NULL;
454 	}
455 }
456 
457 
458 uint8
459 IPCP::NextID()
460 {
461 	return (uint8) atomic_add(&fID, 1);
462 }
463 
464 
465 void
466 IPCP::NewState(ppp_state next)
467 {
468 #if DEBUG
469 	dprintf("IPCP: NewState(%d) state=%d\n", next, State());
470 #endif
471 
472 	// report state changes
473 	if(State() == PPP_INITIAL_STATE && next != State())
474 		UpStarted();
475 	else if(State() == PPP_OPENED_STATE && next != State())
476 		DownStarted();
477 
478 	// maybe we do not need the timer anymore
479 	if(next < PPP_CLOSING_STATE || next == PPP_OPENED_STATE)
480 		fNextTimeout = 0;
481 
482 	fState = next;
483 }
484 
485 
486 void
487 IPCP::TOGoodEvent()
488 {
489 #if DEBUG
490 	dprintf("IPCP: TOGoodEvent() state=%d\n", State());
491 #endif
492 
493 	LockerHelper locker(fLock);
494 
495 	switch(State()) {
496 		case PPP_CLOSING_STATE:
497 			locker.UnlockNow();
498 			SendTerminateRequest();
499 		break;
500 
501 		case PPP_ACK_RCVD_STATE:
502 			NewState(PPP_REQ_SENT_STATE);
503 
504 		case PPP_REQ_SENT_STATE:
505 		case PPP_ACK_SENT_STATE:
506 			locker.UnlockNow();
507 			SendConfigureRequest();
508 		break;
509 
510 		default:
511 			IllegalEvent(PPP_TO_GOOD_EVENT);
512 	}
513 }
514 
515 
516 void
517 IPCP::TOBadEvent()
518 {
519 #if DEBUG
520 	dprintf("IPCP: TOBadEvent() state=%d\n", State());
521 #endif
522 
523 	LockerHelper locker(fLock);
524 
525 	switch(State()) {
526 		case PPP_CLOSING_STATE:
527 			NewState(PPP_INITIAL_STATE);
528 			locker.UnlockNow();
529 			ReportDownEvent();
530 		break;
531 
532 		case PPP_REQ_SENT_STATE:
533 		case PPP_ACK_RCVD_STATE:
534 		case PPP_ACK_SENT_STATE:
535 			NewState(PPP_INITIAL_STATE);
536 			locker.UnlockNow();
537 			ReportUpFailedEvent();
538 		break;
539 
540 		default:
541 			IllegalEvent(PPP_TO_BAD_EVENT);
542 	}
543 }
544 
545 
546 void
547 IPCP::RCREvent(struct mbuf *packet)
548 {
549 #if DEBUG
550 	dprintf("IPCP: RCREvent() state=%d\n", State());
551 #endif
552 
553 	KPPPConfigurePacket request(packet);
554 	KPPPConfigurePacket nak(PPP_CONFIGURE_NAK);
555 	KPPPConfigurePacket reject(PPP_CONFIGURE_REJECT);
556 
557 	// we should not use the same id as the peer
558 	if(fID == mtod(packet, ppp_lcp_packet*)->id)
559 		fID -= 128;
560 
561 	nak.SetID(request.ID());
562 	reject.SetID(request.ID());
563 
564 	// parse each item
565 	ppp_configure_item *item;
566 	in_addr_t *requestedAddress, *wishedAddress = NULL;
567 	for(int32 index = 0; index < request.CountItems(); index++) {
568 		item = request.ItemAt(index);
569 		if(!item)
570 			continue;
571 
572 		// addresses have special handling to reduce code size
573 		switch(item->type) {
574 			case IPCP_ADDRESSES:
575 				// abandoned by the standard
576 			case IPCP_ADDRESS:
577 				wishedAddress = &fPeerRequests.address;
578 			break;
579 
580 			case IPCP_PRIMARY_DNS:
581 				wishedAddress = &fPeerRequests.primaryDNS;
582 			break;
583 
584 			case IPCP_SECONDARY_DNS:
585 				wishedAddress = &fPeerRequests.secondaryDNS;
586 			break;
587 		}
588 
589 		// now parse item
590 		switch(item->type) {
591 			case IPCP_ADDRESSES:
592 				// abandoned by the standard
593 			case IPCP_ADDRESS:
594 			case IPCP_PRIMARY_DNS:
595 			case IPCP_SECONDARY_DNS:
596 				if(item->length != 6) {
597 					// the packet is invalid
598 					m_freem(packet);
599 					NewState(PPP_INITIAL_STATE);
600 					ReportUpFailedEvent();
601 					return;
602 				}
603 
604 				requestedAddress = (in_addr_t*) item->data;
605 				if(*wishedAddress == INADDR_ANY) {
606 					if(*requestedAddress == INADDR_ANY) {
607 						// we do not have an address for you
608 						m_freem(packet);
609 						NewState(PPP_INITIAL_STATE);
610 						ReportUpFailedEvent();
611 						return;
612 					}
613 				} else if(*requestedAddress != *wishedAddress) {
614 					// we do not want this address
615 					ip_item ipItem;
616 					ipItem.type = item->type;
617 					ipItem.length = 6;
618 					ipItem.address = *wishedAddress;
619 					nak.AddItem((ppp_configure_item*) &ipItem);
620 				}
621 			break;
622 
623 //			case IPCP_COMPRESSION_PROTOCOL:
624 				// TODO: implement me!
625 //			break;
626 
627 			default:
628 				reject.AddItem(item);
629 		}
630 	}
631 
632 	// append additional values to the nak
633 	if(!request.ItemWithType(IPCP_ADDRESS) && fPeerRequests.address == INADDR_ANY) {
634 		// The peer did not provide us his address. Tell him to do so.
635 		ip_item ipItem;
636 		ipItem.type = IPCP_ADDRESS;
637 		ipItem.length = 6;
638 		ipItem.address = INADDR_ANY;
639 		nak.AddItem((ppp_configure_item*) &ipItem);
640 	}
641 
642 	if(nak.CountItems() > 0) {
643 		RCRBadEvent(nak.ToMbuf(Interface().MRU(), Interface().PacketOverhead()), NULL);
644 		m_freem(packet);
645 	} else if(reject.CountItems() > 0) {
646 		RCRBadEvent(NULL, reject.ToMbuf(Interface().MRU(),
647 			Interface().PacketOverhead()));
648 		m_freem(packet);
649 	} else
650 		RCRGoodEvent(packet);
651 }
652 
653 
654 void
655 IPCP::RCRGoodEvent(struct mbuf *packet)
656 {
657 #if DEBUG
658 	dprintf("IPCP: RCRGoodEvent() state=%d\n", State());
659 #endif
660 
661 	LockerHelper locker(fLock);
662 
663 	switch(State()) {
664 		case PPP_INITIAL_STATE:
665 			NewState(PPP_ACK_SENT_STATE);
666 			InitializeRestartCount();
667 			locker.UnlockNow();
668 			SendConfigureRequest();
669 			SendConfigureAck(packet);
670 		break;
671 
672 		case PPP_REQ_SENT_STATE:
673 			NewState(PPP_ACK_SENT_STATE);
674 
675 		case PPP_ACK_SENT_STATE:
676 			locker.UnlockNow();
677 			SendConfigureAck(packet);
678 		break;
679 
680 		case PPP_ACK_RCVD_STATE:
681 			NewState(PPP_OPENED_STATE);
682 			locker.UnlockNow();
683 			SendConfigureAck(packet);
684 			ReportUpEvent();
685 		break;
686 
687 		case PPP_OPENED_STATE:
688 			NewState(PPP_ACK_SENT_STATE);
689 			locker.UnlockNow();
690 			SendConfigureRequest();
691 			SendConfigureAck(packet);
692 		break;
693 
694 		default:
695 			m_freem(packet);
696 	}
697 }
698 
699 
700 void
701 IPCP::RCRBadEvent(struct mbuf *nak, struct mbuf *reject)
702 {
703 #if DEBUG
704 	dprintf("IPCP: RCRBadEvent() state=%d\n", State());
705 #endif
706 
707 	LockerHelper locker(fLock);
708 
709 	switch(State()) {
710 		case PPP_OPENED_STATE:
711 			NewState(PPP_REQ_SENT_STATE);
712 			locker.UnlockNow();
713 			SendConfigureRequest();
714 
715 		case PPP_ACK_SENT_STATE:
716 			if(State() == PPP_ACK_SENT_STATE)
717 				NewState(PPP_REQ_SENT_STATE);
718 					// OPENED_STATE might have set this already
719 
720 		case PPP_INITIAL_STATE:
721 		case PPP_REQ_SENT_STATE:
722 		case PPP_ACK_RCVD_STATE:
723 			locker.UnlockNow();
724 			if(nak && ntohs(mtod(nak, ppp_lcp_packet*)->length) > 3)
725 				SendConfigureNak(nak);
726 			else if(reject && ntohs(mtod(reject, ppp_lcp_packet*)->length) > 3)
727 				SendConfigureNak(reject);
728 		return;
729 			// prevents the nak/reject from being m_freem()'d
730 
731 		default:
732 			;
733 	}
734 
735 	if(nak)
736 		m_freem(nak);
737 	if(reject)
738 		m_freem(reject);
739 }
740 
741 
742 void
743 IPCP::RCAEvent(struct mbuf *packet)
744 {
745 #if DEBUG
746 	dprintf("IPCP: RCAEvent() state=%d\n", State());
747 #endif
748 
749 	LockerHelper locker(fLock);
750 
751 	if(fRequestID != mtod(packet, ppp_lcp_packet*)->id) {
752 		// this packet is not a reply to our request
753 
754 		// TODO: log this event
755 		m_freem(packet);
756 		return;
757 	}
758 
759 	// parse this ack
760 	KPPPConfigurePacket ack(packet);
761 	ppp_configure_item *item;
762 	in_addr_t *requestedAddress, *wishedAddress = NULL, *configuredAddress = NULL;
763 	for(int32 index = 0; index < ack.CountItems(); index++) {
764 		item = ack.ItemAt(index);
765 		if(!item)
766 			continue;
767 
768 		// addresses have special handling to reduce code size
769 		switch(item->type) {
770 			case IPCP_ADDRESSES:
771 				// abandoned by the standard
772 			case IPCP_ADDRESS:
773 				wishedAddress = &fLocalRequests.address;
774 				configuredAddress = &fLocalConfiguration.address;
775 			break;
776 
777 			case IPCP_PRIMARY_DNS:
778 				wishedAddress = &fLocalRequests.primaryDNS;
779 				configuredAddress = &fLocalConfiguration.primaryDNS;
780 			break;
781 
782 			case IPCP_SECONDARY_DNS:
783 				wishedAddress = &fLocalRequests.secondaryDNS;
784 				configuredAddress = &fLocalConfiguration.secondaryDNS;
785 			break;
786 		}
787 
788 		// now parse item
789 		switch(item->type) {
790 			case IPCP_ADDRESSES:
791 				// abandoned by the standard
792 			case IPCP_ADDRESS:
793 			case IPCP_PRIMARY_DNS:
794 			case IPCP_SECONDARY_DNS:
795 				requestedAddress = (in_addr_t*) item->data;
796 				if((*wishedAddress == INADDR_ANY && *requestedAddress != INADDR_ANY)
797 						|| *wishedAddress == *requestedAddress)
798 					*configuredAddress = *requestedAddress;
799 			break;
800 
801 //			case IPCP_COMPRESSION_PROTOCOL:
802 				// TODO: implement me
803 //			break;
804 
805 			default:
806 				;
807 		}
808 	}
809 
810 	// if address was not specified we should select the given one
811 	if(!ack.ItemWithType(IPCP_ADDRESS))
812 		fLocalConfiguration.address = fLocalRequests.address;
813 
814 
815 	switch(State()) {
816 		case PPP_INITIAL_STATE:
817 			IllegalEvent(PPP_RCA_EVENT);
818 		break;
819 
820 		case PPP_REQ_SENT_STATE:
821 			NewState(PPP_ACK_RCVD_STATE);
822 			InitializeRestartCount();
823 		break;
824 
825 		case PPP_ACK_RCVD_STATE:
826 			NewState(PPP_REQ_SENT_STATE);
827 			locker.UnlockNow();
828 			SendConfigureRequest();
829 		break;
830 
831 		case PPP_ACK_SENT_STATE:
832 			NewState(PPP_OPENED_STATE);
833 			InitializeRestartCount();
834 			locker.UnlockNow();
835 			ReportUpEvent();
836 		break;
837 
838 		case PPP_OPENED_STATE:
839 			NewState(PPP_REQ_SENT_STATE);
840 			locker.UnlockNow();
841 			SendConfigureRequest();
842 		break;
843 
844 		default:
845 			;
846 	}
847 
848 	m_freem(packet);
849 }
850 
851 
852 void
853 IPCP::RCNEvent(struct mbuf *packet)
854 {
855 #if DEBUG
856 	dprintf("IPCP: RCNEvent() state=%d\n", State());
857 #endif
858 
859 	LockerHelper locker(fLock);
860 
861 	if(fRequestID != mtod(packet, ppp_lcp_packet*)->id) {
862 		// this packet is not a reply to our request
863 
864 		// TODO: log this event
865 		m_freem(packet);
866 		return;
867 	}
868 
869 	// parse this nak/reject
870 	KPPPConfigurePacket nak_reject(packet);
871 	ppp_configure_item *item;
872 	in_addr_t *requestedAddress;
873 	if(nak_reject.Code() == PPP_CONFIGURE_NAK)
874 		for(int32 index = 0; index < nak_reject.CountItems(); index++) {
875 			item = nak_reject.ItemAt(index);
876 			if(!item)
877 				continue;
878 
879 			switch(item->type) {
880 				case IPCP_ADDRESSES:
881 					// abandoned by the standard
882 				case IPCP_ADDRESS:
883 					if(item->length != 6)
884 						continue;
885 
886 					requestedAddress = (in_addr_t*) item->data;
887 					if(fLocalRequests.address == INADDR_ANY
888 							&& *requestedAddress != INADDR_ANY)
889 						fLocalConfiguration.address = *requestedAddress;
890 							// this will be used in our next request
891 				break;
892 
893 //				case IPCP_COMPRESSION_PROTOCOL:
894 					// TODO: implement me!
895 //				break;
896 
897 				case IPCP_PRIMARY_DNS:
898 					if(item->length != 6)
899 						continue;
900 
901 					requestedAddress = (in_addr_t*) item->data;
902 					if(fRequestPrimaryDNS
903 							&& fLocalRequests.primaryDNS == INADDR_ANY
904 							&& *requestedAddress != INADDR_ANY)
905 						fLocalConfiguration.primaryDNS = *requestedAddress;
906 							// this will be used in our next request
907 				break;
908 
909 				case IPCP_SECONDARY_DNS:
910 					if(item->length != 6)
911 						continue;
912 
913 					requestedAddress = (in_addr_t*) item->data;
914 					if(fRequestSecondaryDNS
915 							&& fLocalRequests.secondaryDNS == INADDR_ANY
916 							&& *requestedAddress != INADDR_ANY)
917 						fLocalConfiguration.secondaryDNS = *requestedAddress;
918 							// this will be used in our next request
919 				break;
920 
921 				default:
922 					;
923 			}
924 		}
925 	else if(nak_reject.Code() == PPP_CONFIGURE_REJECT)
926 		for(int32 index = 0; index < nak_reject.CountItems(); index++) {
927 			item = nak_reject.ItemAt(index);
928 			if(!item)
929 				continue;
930 
931 			switch(item->type) {
932 //				case IPCP_COMPRESSION_PROTOCOL:
933 					// TODO: implement me!
934 //				break;
935 
936 				default:
937 					// DNS and addresses must be supported if we set them to auto
938 					m_freem(packet);
939 					NewState(PPP_INITIAL_STATE);
940 					ReportUpFailedEvent();
941 					return;
942 			}
943 		}
944 
945 	switch(State()) {
946 		case PPP_INITIAL_STATE:
947 			IllegalEvent(PPP_RCN_EVENT);
948 		break;
949 
950 		case PPP_REQ_SENT_STATE:
951 		case PPP_ACK_SENT_STATE:
952 			InitializeRestartCount();
953 
954 		case PPP_ACK_RCVD_STATE:
955 		case PPP_OPENED_STATE:
956 			if(State() == PPP_ACK_RCVD_STATE || State() == PPP_OPENED_STATE)
957 				NewState(PPP_REQ_SENT_STATE);
958 			locker.UnlockNow();
959 			SendConfigureRequest();
960 		break;
961 
962 		default:
963 			;
964 	}
965 
966 	m_freem(packet);
967 }
968 
969 
970 void
971 IPCP::RTREvent(struct mbuf *packet)
972 {
973 #if DEBUG
974 	dprintf("IPCP: RTREvent() state=%d\n", State());
975 #endif
976 
977 	LockerHelper locker(fLock);
978 
979 	// we should not use the same ID as the peer
980 	if(fID == mtod(packet, ppp_lcp_packet*)->id)
981 		fID -= 128;
982 
983 	switch(State()) {
984 		case PPP_INITIAL_STATE:
985 			IllegalEvent(PPP_RTR_EVENT);
986 		break;
987 
988 		case PPP_ACK_RCVD_STATE:
989 		case PPP_ACK_SENT_STATE:
990 			NewState(PPP_REQ_SENT_STATE);
991 
992 		case PPP_CLOSING_STATE:
993 		case PPP_REQ_SENT_STATE:
994 			locker.UnlockNow();
995 			SendTerminateAck(packet);
996 		return;
997 			// do not m_freem() packet
998 
999 		case PPP_OPENED_STATE:
1000 			NewState(PPP_CLOSING_STATE);
1001 			ZeroRestartCount();
1002 			locker.UnlockNow();
1003 			SendTerminateAck(packet);
1004 		return;
1005 			// do not m_freem() packet
1006 
1007 		default:
1008 			;
1009 	}
1010 
1011 	m_freem(packet);
1012 }
1013 
1014 
1015 void
1016 IPCP::RTAEvent(struct mbuf *packet)
1017 {
1018 #if DEBUG
1019 	dprintf("IPCP: RTAEvent() state=%d\n", State());
1020 #endif
1021 
1022 	LockerHelper locker(fLock);
1023 
1024 	if(fTerminateID != mtod(packet, ppp_lcp_packet*)->id) {
1025 		// this packet is not a reply to our request
1026 
1027 		// TODO: log this event
1028 		m_freem(packet);
1029 		return;
1030 	}
1031 
1032 	switch(State()) {
1033 		case PPP_INITIAL_STATE:
1034 			IllegalEvent(PPP_RTA_EVENT);
1035 		break;
1036 
1037 		case PPP_CLOSING_STATE:
1038 			NewState(PPP_INITIAL_STATE);
1039 			locker.UnlockNow();
1040 			ReportDownEvent();
1041 		break;
1042 
1043 		case PPP_ACK_RCVD_STATE:
1044 			NewState(PPP_REQ_SENT_STATE);
1045 		break;
1046 
1047 		case PPP_OPENED_STATE:
1048 			NewState(PPP_REQ_SENT_STATE);
1049 			locker.UnlockNow();
1050 			SendConfigureRequest();
1051 		break;
1052 
1053 		default:
1054 			;
1055 	}
1056 
1057 	m_freem(packet);
1058 }
1059 
1060 
1061 void
1062 IPCP::RUCEvent(struct mbuf *packet)
1063 {
1064 #if DEBUG
1065 	dprintf("IPCP: RUCEvent() state=%d\n", State());
1066 #endif
1067 
1068 	SendCodeReject(packet);
1069 }
1070 
1071 
1072 void
1073 IPCP::RXJBadEvent(struct mbuf *packet)
1074 {
1075 #if DEBUG
1076 	dprintf("IPCP: RXJBadEvent() state=%d\n", State());
1077 #endif
1078 
1079 	LockerHelper locker(fLock);
1080 
1081 	switch(State()) {
1082 		case PPP_INITIAL_STATE:
1083 			IllegalEvent(PPP_RXJ_BAD_EVENT);
1084 		break;
1085 
1086 		case PPP_CLOSING_STATE:
1087 			NewState(PPP_INITIAL_STATE);
1088 			locker.UnlockNow();
1089 			ReportDownEvent();
1090 		break;
1091 
1092 		case PPP_REQ_SENT_STATE:
1093 		case PPP_ACK_RCVD_STATE:
1094 		case PPP_ACK_SENT_STATE:
1095 			NewState(PPP_INITIAL_STATE);
1096 			locker.UnlockNow();
1097 			ReportUpFailedEvent();
1098 		break;
1099 
1100 		case PPP_OPENED_STATE:
1101 			NewState(PPP_CLOSING_STATE);
1102 			InitializeRestartCount();
1103 			locker.UnlockNow();
1104 			SendTerminateRequest();
1105 		break;
1106 
1107 		default:
1108 			;
1109 	}
1110 
1111 	m_freem(packet);
1112 }
1113 
1114 
1115 // actions
1116 void
1117 IPCP::IllegalEvent(ppp_event event)
1118 {
1119 	// TODO: update error statistics
1120 	dprintf("IPCP: IllegalEvent(event=%d) state=%d\n", event, State());
1121 }
1122 
1123 
1124 void
1125 IPCP::ReportUpFailedEvent()
1126 {
1127 	// reset configurations
1128 	memset(&fLocalConfiguration, 0, sizeof(ipcp_configuration));
1129 	memset(&fPeerConfiguration, 0, sizeof(ipcp_configuration));
1130 
1131 	UpdateAddresses();
1132 
1133 	UpFailedEvent();
1134 }
1135 
1136 
1137 void
1138 IPCP::ReportUpEvent()
1139 {
1140 	UpdateAddresses();
1141 
1142 	UpEvent();
1143 }
1144 
1145 
1146 void
1147 IPCP::ReportDownEvent()
1148 {
1149 	// reset configurations
1150 	memset(&fLocalConfiguration, 0, sizeof(ipcp_configuration));
1151 	memset(&fPeerConfiguration, 0, sizeof(ipcp_configuration));
1152 
1153 	UpdateAddresses();
1154 
1155 	DownEvent();
1156 }
1157 
1158 
1159 void
1160 IPCP::InitializeRestartCount()
1161 {
1162 	fRequestCounter = fMaxRequest;
1163 	fTerminateCounter = fMaxTerminate;
1164 	fNakCounter = fMaxNak;
1165 }
1166 
1167 
1168 void
1169 IPCP::ZeroRestartCount()
1170 {
1171 	fRequestCounter = 0;
1172 	fTerminateCounter = 0;
1173 	fNakCounter = 0;
1174 }
1175 
1176 
1177 bool
1178 IPCP::SendConfigureRequest()
1179 {
1180 #if DEBUG
1181 	dprintf("IPCP: SendConfigureRequest() state=%d\n", State());
1182 #endif
1183 
1184 	LockerHelper locker(fLock);
1185 	--fRequestCounter;
1186 	fNextTimeout = system_time() + PPP_STATE_MACHINE_TIMEOUT;
1187 	locker.UnlockNow();
1188 
1189 	KPPPConfigurePacket request(PPP_CONFIGURE_REQUEST);
1190 	request.SetID(NextID());
1191 	fRequestID = request.ID();
1192 	ip_item ipItem;
1193 	ipItem.length = 6;
1194 
1195 	// add address
1196 	ipItem.type = IPCP_ADDRESS;
1197 	if(fLocalRequests.address == INADDR_ANY)
1198 		ipItem.address = fLocalConfiguration.address;
1199 	else
1200 		ipItem.address = fLocalRequests.address;
1201 	request.AddItem((ppp_configure_item*) &ipItem);
1202 
1203 #if DEBUG
1204 	dprintf("IPCP: SCR: confaddr=%lX; reqaddr=%lX; addr=%lX\n",
1205 		fLocalConfiguration.address, fLocalRequests.address,
1206 		((ip_item*)request.ItemAt(0))->address);
1207 #endif
1208 
1209 	// add primary DNS (if needed)
1210 	if(fRequestPrimaryDNS && fLocalRequests.primaryDNS == INADDR_ANY) {
1211 		ipItem.type = IPCP_PRIMARY_DNS;
1212 		ipItem.address = fLocalConfiguration.primaryDNS;
1213 			// at first this is 0.0.0.0, but a nak might have set it to a correct value
1214 		request.AddItem((ppp_configure_item*) &ipItem);
1215 	}
1216 
1217 	// add secondary DNS (if needed)
1218 	if(fRequestSecondaryDNS && fLocalRequests.primaryDNS == INADDR_ANY) {
1219 		ipItem.type = IPCP_SECONDARY_DNS;
1220 		ipItem.address = fLocalConfiguration.secondaryDNS;
1221 			// at first this is 0.0.0.0, but a nak might have set it to a correct value
1222 		request.AddItem((ppp_configure_item*) &ipItem);
1223 	}
1224 
1225 	// TODO: add VJC support
1226 
1227 	return Send(request.ToMbuf(Interface().MRU(),
1228 		Interface().PacketOverhead())) == B_OK;
1229 }
1230 
1231 
1232 bool
1233 IPCP::SendConfigureAck(struct mbuf *packet)
1234 {
1235 #if DEBUG
1236 	dprintf("IPCP: SendConfigureAck() state=%d\n", State());
1237 #endif
1238 
1239 	if(!packet)
1240 		return false;
1241 
1242 	mtod(packet, ppp_lcp_packet*)->code = PPP_CONFIGURE_ACK;
1243 	KPPPConfigurePacket ack(packet);
1244 
1245 	// verify items
1246 	ppp_configure_item *item;
1247 	in_addr_t *requestedAddress, *wishedAddress = NULL, *configuredAddress = NULL;
1248 	for(int32 index = 0; index < ack.CountItems(); index++) {
1249 		item = ack.ItemAt(index);
1250 		if(!item)
1251 			continue;
1252 
1253 		// addresses have special handling to reduce code size
1254 		switch(item->type) {
1255 			case IPCP_ADDRESSES:
1256 				// abandoned by the standard
1257 			case IPCP_ADDRESS:
1258 				wishedAddress = &fPeerRequests.address;
1259 				configuredAddress = &fPeerConfiguration.address;
1260 			break;
1261 
1262 			case IPCP_PRIMARY_DNS:
1263 				wishedAddress = &fPeerRequests.primaryDNS;
1264 				configuredAddress = &fPeerConfiguration.primaryDNS;
1265 			break;
1266 
1267 			case IPCP_SECONDARY_DNS:
1268 				wishedAddress = &fPeerRequests.secondaryDNS;
1269 				configuredAddress = &fPeerConfiguration.secondaryDNS;
1270 			break;
1271 		}
1272 
1273 		// now parse item
1274 		switch(item->type) {
1275 			case IPCP_ADDRESSES:
1276 				// abandoned by the standard
1277 			case IPCP_ADDRESS:
1278 			case IPCP_PRIMARY_DNS:
1279 			case IPCP_SECONDARY_DNS:
1280 				requestedAddress = (in_addr_t*) item->data;
1281 				if((*wishedAddress == INADDR_ANY && *requestedAddress != INADDR_ANY)
1282 						|| *wishedAddress == *requestedAddress)
1283 					*configuredAddress = *requestedAddress;
1284 			break;
1285 
1286 //			case IPCP_COMPRESSION_PROTOCOL:
1287 				// TODO: implement me!
1288 //			break;
1289 
1290 			default:
1291 				;
1292 		}
1293 	}
1294 
1295 	// if address was not specified we should select the given one
1296 	if(!ack.ItemWithType(IPCP_ADDRESS))
1297 		fPeerConfiguration.address = fPeerRequests.address;
1298 
1299 	return Send(packet) == B_OK;
1300 }
1301 
1302 
1303 bool
1304 IPCP::SendConfigureNak(struct mbuf *packet)
1305 {
1306 #if DEBUG
1307 	dprintf("IPCP: SendConfigureNak() state=%d\n", State());
1308 #endif
1309 
1310 	if(!packet)
1311 		return false;
1312 
1313 	ppp_lcp_packet *nak = mtod(packet, ppp_lcp_packet*);
1314 	if(nak->code == PPP_CONFIGURE_NAK) {
1315 		if(fNakCounter == 0) {
1316 			// We sent enough naks. Let's try a reject.
1317 			nak->code = PPP_CONFIGURE_REJECT;
1318 		} else
1319 			--fNakCounter;
1320 	}
1321 
1322 	return Send(packet) == B_OK;
1323 }
1324 
1325 
1326 bool
1327 IPCP::SendTerminateRequest()
1328 {
1329 #if DEBUG
1330 	dprintf("IPCP: SendTerminateRequest() state=%d\n", State());
1331 #endif
1332 
1333 	LockerHelper locker(fLock);
1334 	--fTerminateCounter;
1335 	fNextTimeout = system_time() + PPP_STATE_MACHINE_TIMEOUT;
1336 	locker.UnlockNow();
1337 
1338 	struct mbuf *packet = m_gethdr(MT_DATA);
1339 	if(!packet)
1340 		return false;
1341 
1342 	packet->m_pkthdr.len = packet->m_len = 4;
1343 
1344 	// reserve some space for other protocols
1345 	packet->m_data += Interface().PacketOverhead();
1346 
1347 	ppp_lcp_packet *request = mtod(packet, ppp_lcp_packet*);
1348 	request->code = PPP_TERMINATE_REQUEST;
1349 	request->id = fTerminateID = NextID();
1350 	request->length = htons(4);
1351 
1352 	return Send(packet) == B_OK;
1353 }
1354 
1355 
1356 bool
1357 IPCP::SendTerminateAck(struct mbuf *request = NULL)
1358 {
1359 #if DEBUG
1360 	dprintf("IPCP: SendTerminateAck() state=%d\n", State());
1361 #endif
1362 
1363 	struct mbuf *reply = request;
1364 
1365 	ppp_lcp_packet *ack;
1366 
1367 	if(!reply) {
1368 		reply = m_gethdr(MT_DATA);
1369 		if(!reply)
1370 			return false;
1371 
1372 		reply->m_data += Interface().PacketOverhead();
1373 		reply->m_pkthdr.len = reply->m_len = 4;
1374 
1375 		ack = mtod(reply, ppp_lcp_packet*);
1376 		ack->id = NextID();
1377 	} else
1378 		ack = mtod(reply, ppp_lcp_packet*);
1379 
1380 	ack->code = PPP_TERMINATE_ACK;
1381 	ack->length = htons(4);
1382 
1383 	return Send(reply) == B_OK;
1384 }
1385 
1386 
1387 bool
1388 IPCP::SendCodeReject(struct mbuf *packet)
1389 {
1390 #if DEBUG
1391 	dprintf("IPCP: SendCodeReject() state=%d\n", State());
1392 #endif
1393 
1394 	if(!packet)
1395 		return false;
1396 
1397 	M_PREPEND(packet, 4);
1398 		// add some space for the header
1399 
1400 	// adjust packet if too big
1401 	int32 adjust = Interface().MRU();
1402 	if(packet->m_flags & M_PKTHDR) {
1403 		adjust -= packet->m_pkthdr.len;
1404 	} else
1405 		adjust -= packet->m_len;
1406 
1407 	if(adjust < 0)
1408 		m_adj(packet, adjust);
1409 
1410 	ppp_lcp_packet *reject = mtod(packet, ppp_lcp_packet*);
1411 	reject->code = PPP_CODE_REJECT;
1412 	reject->id = NextID();
1413 	if(packet->m_flags & M_PKTHDR)
1414 		reject->length = htons(packet->m_pkthdr.len);
1415 	else
1416 		reject->length = htons(packet->m_len);
1417 
1418 	return Send(packet) == B_OK;
1419 }
1420