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