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