184b580c4SWaldemar Kornewald/*
22f13f213SWaldemar Kornewald * Copyright 2003-2006, Waldemar Kornewald <wkornew@gmx.net>
384b580c4SWaldemar Kornewald * Distributed under the terms of the MIT License.
484b580c4SWaldemar Kornewald */
5ca43389aSWaldemar Kornewald
6cdee6f97SWaldemar Kornewald#if DEBUG
7cdee6f97SWaldemar Kornewald#include <cstdio>
8cdee6f97SWaldemar Kornewald#endif
9cdee6f97SWaldemar Kornewald
10ca43389aSWaldemar Kornewald#include "Protocol.h"
11b8f24e83SWaldemar Kornewald#include "IPCP.h"
12ca43389aSWaldemar Kornewald#include <KPPPConfigurePacket.h>
13ca43389aSWaldemar Kornewald#include <KPPPInterface.h>
141cea3d85SWaldemar Kornewald#include <settings_tools.h>
15ca43389aSWaldemar Kornewald
16e3724c38Smshlyn#include <PPPoEDevice.h>
17e3724c38Smshlyn
18ca43389aSWaldemar Kornewald#include <cstring>
19e3724c38Smshlyn
20e3724c38Smshlyn#include <arpa/inet.h>
21e3724c38Smshlyn#include <net_buffer.h>
22e3724c38Smshlyn#include <net_stack.h>
23e3724c38Smshlyn#include <net/route.h>
24ca43389aSWaldemar Kornewald#include <sys/sockio.h>
25ca43389aSWaldemar Kornewald
26e3724c38Smshlyn// For updating resolv.conf
27e3724c38Smshlyn#include <ctype.h>
28e3724c38Smshlyn#include <fcntl.h>
29e3724c38Smshlyn#include <stdio.h>
30e3724c38Smshlyn#include <stdlib.h>
31e3724c38Smshlyn#include <string.h>
32e3724c38Smshlyn#include <unistd.h>
33e3724c38Smshlyn
34e3724c38Smshlyn#define RESOLV_CONF_FILE "/boot/system/settings/network/resolv.conf"
35e3724c38Smshlyn
36e3724c38Smshlynextern net_buffer_module_info *gBufferModule;
37e3724c38Smshlynstatic struct net_datalink_module_info *sDatalinkModule;
38e3724c38Smshlynstatic struct net_stack_module_info *sStackModule;
39ca43389aSWaldemar Kornewald
40cdee6f97SWaldemar Kornewald#if DEBUG
41cdee6f97SWaldemar Kornewald#include <unistd.h>
42cdee6f97SWaldemar Kornewald
43cdee6f97SWaldemar Kornewaldstatic int sFD;
44cdee6f97SWaldemar Kornewald	// the file descriptor for debug output
45cdee6f97SWaldemar Kornewaldstatic char sDigits[] = "0123456789ABCDEF";
46cdee6f97SWaldemar Kornewaldvoid
47e3724c38Smshlyndump_packet(net_buffer *packet, const char *direction)
48cdee6f97SWaldemar Kornewald{
49e3724c38Smshlyn	if (!packet)
50cdee6f97SWaldemar Kornewald		return;
51e3724c38Smshlyn
52cdee6f97SWaldemar Kornewald	uint8 *data = mtod(packet, uint8*);
53cdee6f97SWaldemar Kornewald	uint8 buffer[128];
54cdee6f97SWaldemar Kornewald	uint8 bufferIndex = 0;
55e3724c38Smshlyn
56cdee6f97SWaldemar Kornewald	sprintf((char*) buffer, "Dumping %s packet;len=%ld;pkthdr.len=%d\n", direction,
57cdee6f97SWaldemar Kornewald		packet->m_len, packet->m_flags & M_PKTHDR ? packet->m_pkthdr.len : -1);
58cdee6f97SWaldemar Kornewald	write(sFD, buffer, strlen((char*) buffer));
59e3724c38Smshlyn
60e3724c38Smshlyn	for (uint32 index = 0; index < packet->m_len; index++) {
61cdee6f97SWaldemar Kornewald		buffer[bufferIndex++] = sDigits[data[index] >> 4];
62cdee6f97SWaldemar Kornewald		buffer[bufferIndex++] = sDigits[data[index] & 0x0F];
63e3724c38Smshlyn		if (bufferIndex == 32 || index == packet->m_len - 1) {
64cdee6f97SWaldemar Kornewald			buffer[bufferIndex++] = '\n';
65cdee6f97SWaldemar Kornewald			buffer[bufferIndex] = 0;
66cdee6f97SWaldemar Kornewald			write(sFD, buffer, strlen((char*) buffer));
67cdee6f97SWaldemar Kornewald			bufferIndex = 0;
68cdee6f97SWaldemar Kornewald		}
69cdee6f97SWaldemar Kornewald	}
70cdee6f97SWaldemar Kornewald}
71cdee6f97SWaldemar Kornewald#endif
72cdee6f97SWaldemar Kornewald
73cdee6f97SWaldemar Kornewald
746ff76cdaSWaldemar Kornewaldstatic const bigtime_t kIPCPStateMachineTimeout = 3000000;
75ca43389aSWaldemar Kornewald	// 3 seconds
76ca43389aSWaldemar Kornewald
77ca43389aSWaldemar Kornewald
781cea3d85SWaldemar KornewaldIPCP::IPCP(KPPPInterface& interface, driver_parameter *settings)
791cea3d85SWaldemar Kornewald	: KPPPProtocol("IPCP", PPP_NCP_PHASE, IPCP_PROTOCOL, PPP_PROTOCOL_LEVEL,
80ca43389aSWaldemar Kornewald		AF_INET, 0, interface, settings, PPP_INCLUDES_NCP),
816cfb4dcaSWaldemar Kornewald	fDefaultRoute(NULL),
82ca43389aSWaldemar Kornewald	fRequestPrimaryDNS(false),
83ca43389aSWaldemar Kornewald	fRequestSecondaryDNS(false),
84ca43389aSWaldemar Kornewald	fState(PPP_INITIAL_STATE),
85ca43389aSWaldemar Kornewald	fID(system_time() & 0xFF),
86ca43389aSWaldemar Kornewald	fMaxRequest(10),
87ca43389aSWaldemar Kornewald	fMaxTerminate(2),
88ca43389aSWaldemar Kornewald	fMaxNak(5),
89ca43389aSWaldemar Kornewald	fRequestID(0),
90ca43389aSWaldemar Kornewald	fTerminateID(0),
912f13f213SWaldemar Kornewald	fNextTimeout(0)
92ca43389aSWaldemar Kornewald{
93abdb7d1aSWaldemar Kornewald	// reset configurations
94abdb7d1aSWaldemar Kornewald	memset(&fLocalConfiguration, 0, sizeof(ipcp_configuration));
95abdb7d1aSWaldemar Kornewald	memset(&fPeerConfiguration, 0, sizeof(ipcp_configuration));
96e3724c38Smshlyn
97abdb7d1aSWaldemar Kornewald	// reset requests
98abdb7d1aSWaldemar Kornewald	memset(&fLocalRequests, 0, sizeof(ipcp_requests));
99abdb7d1aSWaldemar Kornewald	memset(&fPeerRequests, 0, sizeof(ipcp_requests));
100e3724c38Smshlyn
101abdb7d1aSWaldemar Kornewald	// Parse settings:
102abdb7d1aSWaldemar Kornewald	// "Local" and "Peer" describe each side's settings
103abdb7d1aSWaldemar Kornewald	ParseSideRequests(get_parameter_with_name(IPCP_LOCAL_SIDE_KEY, Settings()),
104abdb7d1aSWaldemar Kornewald		PPP_LOCAL_SIDE);
105abdb7d1aSWaldemar Kornewald	ParseSideRequests(get_parameter_with_name(IPCP_PEER_SIDE_KEY, Settings()),
106abdb7d1aSWaldemar Kornewald		PPP_PEER_SIDE);
107e3724c38Smshlyn
108e3724c38Smshlyn	get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule);
109e3724c38Smshlyn	get_module(NET_DATALINK_MODULE_NAME, (module_info **)&sDatalinkModule);
110cdee6f97SWaldemar Kornewald#if DEBUG
111cdee6f97SWaldemar Kornewald	sFD = open("/boot/home/ipcpdebug", O_WRONLY | O_CREAT | O_TRUNC);
112cdee6f97SWaldemar Kornewald#endif
113ca43389aSWaldemar Kornewald}
114ca43389aSWaldemar Kornewald
115ca43389aSWaldemar Kornewald
116ca43389aSWaldemar KornewaldIPCP::~IPCP()
117ce0b86e9SWaldemar Kornewald{
118e3724c38Smshlyn
119e3724c38Smshlyn	put_module(NET_DATALINK_MODULE_NAME);
120e3724c38Smshlyn	put_module(NET_STACK_MODULE_NAME);
121cdee6f97SWaldemar Kornewald#if DEBUG
122cdee6f97SWaldemar Kornewald	close(sFD);
123cdee6f97SWaldemar Kornewald#endif
124ce0b86e9SWaldemar Kornewald}
125ce0b86e9SWaldemar Kornewald
126ce0b86e9SWaldemar Kornewald
127ce0b86e9SWaldemar Kornewaldvoid
128ce0b86e9SWaldemar KornewaldIPCP::Uninit()
129ca43389aSWaldemar Kornewald{
1306cfb4dcaSWaldemar Kornewald	RemoveRoutes();
131ca43389aSWaldemar Kornewald}
132ca43389aSWaldemar Kornewald
133ca43389aSWaldemar Kornewald
13493a59056SWaldemar Kornewaldstatus_t
13593a59056SWaldemar KornewaldIPCP::StackControl(uint32 op, void *data)
13693a59056SWaldemar Kornewald{
13784b580c4SWaldemar Kornewald	TRACE("IPCP: StackControl(op=%ld)\n", op);
138e3724c38Smshlyn
13993a59056SWaldemar Kornewald	// TODO:
14093a59056SWaldemar Kornewald	// check values
141e3724c38Smshlyn
142e3724c38Smshlyn	switch (op) {
14393a59056SWaldemar Kornewald		case SIOCSIFADDR:
14493a59056SWaldemar Kornewald		break;
145e3724c38Smshlyn
14693a59056SWaldemar Kornewald		case SIOCSIFFLAGS:
14793a59056SWaldemar Kornewald		break;
148e3724c38Smshlyn
14993a59056SWaldemar Kornewald		case SIOCSIFDSTADDR:
15093a59056SWaldemar Kornewald		break;
151e3724c38Smshlyn
15293a59056SWaldemar Kornewald		case SIOCSIFNETMASK:
15393a59056SWaldemar Kornewald		break;
154e3724c38Smshlyn
15593a59056SWaldemar Kornewald		default:
156ceff2b88SAlexander von Gluck IV			ERROR("IPCP: Unknown ioctl: %" B_PRIu32 "\n", op);
1571cea3d85SWaldemar Kornewald			return KPPPProtocol::StackControl(op, data);
15893a59056SWaldemar Kornewald	}
159e3724c38Smshlyn
16093a59056SWaldemar Kornewald	return B_OK;
16193a59056SWaldemar Kornewald}
16293a59056SWaldemar Kornewald
16393a59056SWaldemar Kornewald
164ca43389aSWaldemar Kornewaldbool
165ca43389aSWaldemar KornewaldIPCP::Up()
166ca43389aSWaldemar Kornewald{
16784b580c4SWaldemar Kornewald	TRACE("IPCP: Up() state=%d\n", State());
168e3724c38Smshlyn
169ca43389aSWaldemar Kornewald	// Servers do not send a configure-request when Up() is called. They wait until
170ca43389aSWaldemar Kornewald	// the client requests this protocol.
171e3724c38Smshlyn	if (Interface().Mode() == PPP_SERVER_MODE)
172ca43389aSWaldemar Kornewald		return true;
173e3724c38Smshlyn
174e3724c38Smshlyn	switch (State()) {
175ca43389aSWaldemar Kornewald		case PPP_INITIAL_STATE:
176ca43389aSWaldemar Kornewald			NewState(PPP_REQ_SENT_STATE);
177ca43389aSWaldemar Kornewald			InitializeRestartCount();
178ca43389aSWaldemar Kornewald			SendConfigureRequest();
179ca43389aSWaldemar Kornewald		break;
180e3724c38Smshlyn
181ca43389aSWaldemar Kornewald		default:
182ca43389aSWaldemar Kornewald			;
183ca43389aSWaldemar Kornewald	}
184e3724c38Smshlyn
185ca43389aSWaldemar Kornewald	return true;
186ca43389aSWaldemar Kornewald}
187ca43389aSWaldemar Kornewald
188ca43389aSWaldemar Kornewald
189ca43389aSWaldemar Kornewaldbool
190ca43389aSWaldemar KornewaldIPCP::Down()
191ca43389aSWaldemar Kornewald{
19284b580c4SWaldemar Kornewald	TRACE("IPCP: Down() state=%d\n", State());
193e3724c38Smshlyn
194e3724c38Smshlyn	switch (Interface().Phase()) {
195ca43389aSWaldemar Kornewald		case PPP_DOWN_PHASE:
196ca43389aSWaldemar Kornewald			// interface finished terminating
197ca43389aSWaldemar Kornewald			NewState(PPP_INITIAL_STATE);
198ca43389aSWaldemar Kornewald			ReportDownEvent();
199ca43389aSWaldemar Kornewald				// this will also reset and update addresses
200ca43389aSWaldemar Kornewald		break;
201e3724c38Smshlyn
202ca43389aSWaldemar Kornewald/*		case PPP_TERMINATION_PHASE:
203ca43389aSWaldemar Kornewald			// interface is terminating
204ca43389aSWaldemar Kornewald		break;
205e3724c38Smshlyn
206ca43389aSWaldemar Kornewald		case PPP_ESTABLISHMENT_PHASE:
207ca43389aSWaldemar Kornewald			// interface is reconfiguring
208ca43389aSWaldemar Kornewald		break;
209e3724c38Smshlyn*/
210ca43389aSWaldemar Kornewald		case PPP_ESTABLISHED_PHASE:
211ca43389aSWaldemar Kornewald			// terminate this NCP individually (block until we finished terminating)
212e3724c38Smshlyn			if (State() != PPP_INITIAL_STATE && State() != PPP_CLOSING_STATE) {
213ca43389aSWaldemar Kornewald				NewState(PPP_CLOSING_STATE);
214ca43389aSWaldemar Kornewald				InitializeRestartCount();
215ca43389aSWaldemar Kornewald				SendTerminateRequest();
216ca43389aSWaldemar Kornewald			}
217e3724c38Smshlyn
218e3724c38Smshlyn			while (State() == PPP_CLOSING_STATE)
219ca43389aSWaldemar Kornewald				snooze(50000);
220ca43389aSWaldemar Kornewald		break;
221e3724c38Smshlyn
222ca43389aSWaldemar Kornewald		default:
223ca43389aSWaldemar Kornewald			;
224ca43389aSWaldemar Kornewald	}
225e3724c38Smshlyn
226ca43389aSWaldemar Kornewald	return true;
227ca43389aSWaldemar Kornewald}
228ca43389aSWaldemar Kornewald
229ca43389aSWaldemar Kornewald
230ca43389aSWaldemar Kornewaldstatus_t
231e3724c38SmshlynIPCP::Send(net_buffer *packet, uint16 protocolNumber)
232ca43389aSWaldemar Kornewald{
23384b580c4SWaldemar Kornewald	TRACE("IPCP: Send(0x%X)\n", protocolNumber);
234e3724c38Smshlyn
235e3724c38Smshlyn	if ((protocolNumber == IP_PROTOCOL && State() == PPP_OPENED_STATE)
236cdee6f97SWaldemar Kornewald			|| protocolNumber == IPCP_PROTOCOL) {
237cdee6f97SWaldemar Kornewald#if DEBUG
238cdee6f97SWaldemar Kornewald		dump_packet(packet, "outgoing");
239cdee6f97SWaldemar Kornewald#endif
240cdee6f97SWaldemar Kornewald		Interface().UpdateIdleSince();
24193a59056SWaldemar Kornewald		return SendToNext(packet, protocolNumber);
242cdee6f97SWaldemar Kornewald	}
243e3724c38Smshlyn
24484b580c4SWaldemar Kornewald	ERROR("IPCP: Send() failed because of wrong state or protocol number!\n");
245e3724c38Smshlyn
246e3724c38Smshlyn	gBufferModule->free(packet);
24793a59056SWaldemar Kornewald	return B_ERROR;
248ca43389aSWaldemar Kornewald}
249ca43389aSWaldemar Kornewald
250ca43389aSWaldemar Kornewald
251ca43389aSWaldemar Kornewaldstatus_t
252e3724c38SmshlynIPCP::Receive(net_buffer *packet, uint16 protocolNumber)
253ca43389aSWaldemar Kornewald{
25484b580c4SWaldemar Kornewald	TRACE("IPCP: Receive(0x%X)\n", protocolNumber);
255e3724c38Smshlyn
256e3724c38Smshlyn	if (!packet)
257ca43389aSWaldemar Kornewald		return B_ERROR;
258e3724c38Smshlyn
259e3724c38Smshlyn	if (protocolNumber == IP_PROTOCOL)
2608dad9b1eSWaldemar Kornewald		return ReceiveIPPacket(packet, protocolNumber);
261e3724c38Smshlyn
262e3724c38Smshlyn	if (protocolNumber != IPCP_PROTOCOL)
263ca43389aSWaldemar Kornewald		return PPP_UNHANDLED;
264e3724c38Smshlyn
265e3724c38Smshlyn	NetBufferHeaderReader<ppp_lcp_packet> bufferheader(packet);
266e3724c38Smshlyn	if (bufferheader.Status() != B_OK)
267ca43389aSWaldemar Kornewald		return B_ERROR;
268e3724c38Smshlyn	ppp_lcp_packet &data = bufferheader.Data();
269e3724c38Smshlyn
270e3724c38Smshlyn	if (ntohs(data.length) < 4)
271e3724c38Smshlyn		return B_ERROR;
272e3724c38Smshlyn
273ca43389aSWaldemar Kornewald	// packet is freed by event methods
274e3724c38Smshlyn	switch (data.code) {
275ca43389aSWaldemar Kornewald		case PPP_CONFIGURE_REQUEST:
276ca43389aSWaldemar Kornewald			RCREvent(packet);
277ca43389aSWaldemar Kornewald		break;
278e3724c38Smshlyn
279ca43389aSWaldemar Kornewald		case PPP_CONFIGURE_ACK:
280ca43389aSWaldemar Kornewald			RCAEvent(packet);
281ca43389aSWaldemar Kornewald		break;
282e3724c38Smshlyn
283ca43389aSWaldemar Kornewald		case PPP_CONFIGURE_NAK:
284ca43389aSWaldemar Kornewald		case PPP_CONFIGURE_REJECT:
285ca43389aSWaldemar Kornewald			RCNEvent(packet);
286ca43389aSWaldemar Kornewald		break;
287e3724c38Smshlyn
288ca43389aSWaldemar Kornewald		case PPP_TERMINATE_REQUEST:
289ca43389aSWaldemar Kornewald			RTREvent(packet);
290ca43389aSWaldemar Kornewald		break;
291e3724c38Smshlyn
292ca43389aSWaldemar Kornewald		case PPP_TERMINATE_ACK:
293ca43389aSWaldemar Kornewald			RTAEvent(packet);
294ca43389aSWaldemar Kornewald		break;
295e3724c38Smshlyn
296ca43389aSWaldemar Kornewald		case PPP_CODE_REJECT:
297ca43389aSWaldemar Kornewald			RXJBadEvent(packet);
298ca43389aSWaldemar Kornewald				// we implemented the minimum requirements
299ca43389aSWaldemar Kornewald		break;
300e3724c38Smshlyn
301ca43389aSWaldemar Kornewald		default:
302ca43389aSWaldemar Kornewald			RUCEvent(packet);
303ca43389aSWaldemar Kornewald			return PPP_REJECTED;
304ca43389aSWaldemar Kornewald	}
305e3724c38Smshlyn
306ca43389aSWaldemar Kornewald	return B_OK;
307ca43389aSWaldemar Kornewald}
308ca43389aSWaldemar Kornewald
309ca43389aSWaldemar Kornewald
310ca43389aSWaldemar Kornewaldstatus_t
311e3724c38SmshlynIPCP::ReceiveIPPacket(net_buffer *packet, uint16 protocolNumber)
312ca43389aSWaldemar Kornewald{
313e3724c38Smshlyn	if (protocolNumber != IP_PROTOCOL || State() != PPP_OPENED_STATE)
314ca43389aSWaldemar Kornewald		return PPP_UNHANDLED;
315e3724c38Smshlyn
316ca43389aSWaldemar Kornewald	// TODO: add VJC support (the packet would be decoded here)
317e3724c38Smshlyn
318cd6365c7SJérôme Duval	if (packet) {
319cdee6f97SWaldemar Kornewald#if DEBUG
320cdee6f97SWaldemar Kornewald		dump_packet(packet, "incoming");
321cdee6f97SWaldemar Kornewald#endif
322cdee6f97SWaldemar Kornewald		Interface().UpdateIdleSince();
323e3724c38Smshlyn
324e3724c38Smshlyn		TRACE("We got 1 IP packet from %s::%s\n", __FILE__, __func__);
325e3724c38Smshlyn		gBufferModule->free(packet);
326ca43389aSWaldemar Kornewald		return B_OK;
327ca43389aSWaldemar Kornewald	} else {
32884b580c4SWaldemar Kornewald		ERROR("IPCP: Error: Could not find input function for IP!\n");
329e3724c38Smshlyn		gBufferModule->free(packet);
330ca43389aSWaldemar Kornewald		return B_ERROR;
331ca43389aSWaldemar Kornewald	}
332ca43389aSWaldemar Kornewald}
333ca43389aSWaldemar Kornewald
334ca43389aSWaldemar Kornewald
335ca43389aSWaldemar Kornewaldvoid
336ca43389aSWaldemar KornewaldIPCP::Pulse()
337ca43389aSWaldemar Kornewald{
338e3724c38Smshlyn	if (fNextTimeout == 0 || fNextTimeout > system_time())
339ca43389aSWaldemar Kornewald		return;
340ca43389aSWaldemar Kornewald	fNextTimeout = 0;
341e3724c38Smshlyn
342e3724c38Smshlyn	switch (State()) {
343ca43389aSWaldemar Kornewald		case PPP_CLOSING_STATE:
344e3724c38Smshlyn			if (fTerminateCounter <= 0)
345ca43389aSWaldemar Kornewald				TOBadEvent();
346ca43389aSWaldemar Kornewald			else
347ca43389aSWaldemar Kornewald				TOGoodEvent();
348ca43389aSWaldemar Kornewald		break;
349e3724c38Smshlyn
350ca43389aSWaldemar Kornewald		case PPP_REQ_SENT_STATE:
351ca43389aSWaldemar Kornewald		case PPP_ACK_RCVD_STATE:
352ca43389aSWaldemar Kornewald		case PPP_ACK_SENT_STATE:
353e3724c38Smshlyn			if (fRequestCounter <= 0)
354ca43389aSWaldemar Kornewald				TOBadEvent();
355ca43389aSWaldemar Kornewald			else
356ca43389aSWaldemar Kornewald				TOGoodEvent();
357ca43389aSWaldemar Kornewald		break;
358e3724c38Smshlyn
359ca43389aSWaldemar Kornewald		default:
360ca43389aSWaldemar Kornewald			;
361ca43389aSWaldemar Kornewald	}
362ca43389aSWaldemar Kornewald}
363ca43389aSWaldemar Kornewald
364ca43389aSWaldemar Kornewald
365ca43389aSWaldemar Kornewaldbool
3661cea3d85SWaldemar KornewaldIPCP::ParseSideRequests(const driver_parameter *requests, ppp_side side)
367ca43389aSWaldemar Kornewald{
368e3724c38Smshlyn	if (!requests)
3691cea3d85SWaldemar Kornewald		return false;
370e3724c38Smshlyn
371ca43389aSWaldemar Kornewald	ipcp_requests *selectedRequests;
372e3724c38Smshlyn
373e3724c38Smshlyn	if (side == PPP_LOCAL_SIDE) {
374ca43389aSWaldemar Kornewald		selectedRequests = &fLocalRequests;
375ca43389aSWaldemar Kornewald		fRequestPrimaryDNS = fRequestSecondaryDNS = false;
376ca43389aSWaldemar Kornewald	} else
377ca43389aSWaldemar Kornewald		selectedRequests = &fPeerRequests;
378e3724c38Smshlyn
379ca43389aSWaldemar Kornewald	memset(selectedRequests, 0, sizeof(ipcp_requests));
380ca43389aSWaldemar Kornewald		// reset current requests
381e3724c38Smshlyn
382ca43389aSWaldemar Kornewald	// The following values are allowed:
383ca43389aSWaldemar Kornewald	//  "Address"		the ip address that will be suggested
384ca43389aSWaldemar Kornewald	//  "Netmask"		the netmask that should be used
385ca43389aSWaldemar Kornewald	//  "PrimaryDNS"	primary DNS server
386ca43389aSWaldemar Kornewald	//  "SecondaryDNS"	secondary DNS server
387ca43389aSWaldemar Kornewald	// Setting any value to 0.0.0.0 or "auto" means it should be chosen automatically.
388e3724c38Smshlyn
389ca43389aSWaldemar Kornewald	in_addr_t address = INADDR_ANY;
390e3724c38Smshlyn	for (int32 index = 0; index < requests->parameter_count; index++) {
391e3724c38Smshlyn		if (requests->parameters[index].value_count == 0)
392ca43389aSWaldemar Kornewald			continue;
393e3724c38Smshlyn
394ca43389aSWaldemar Kornewald		// all values are IP addresses, so parse the address here
395e3724c38Smshlyn		if (strcasecmp(requests->parameters[index].values[0], "auto")) {
396ca43389aSWaldemar Kornewald			address = inet_addr(requests->parameters[index].values[0]);
397e3724c38Smshlyn			// address = INADDR_ANY;
398e3724c38Smshlyn			if (address == INADDR_NONE)
399ca43389aSWaldemar Kornewald				continue;
400ca43389aSWaldemar Kornewald		}
401e3724c38Smshlyn
402e3724c38Smshlyn		if (!strcasecmp(requests->parameters[index].name, IPCP_IP_ADDRESS_KEY))
403ca43389aSWaldemar Kornewald			selectedRequests->address = address;
404e3724c38Smshlyn		else if (!strcasecmp(requests->parameters[index].name, IPCP_NETMASK_KEY))
405ca43389aSWaldemar Kornewald			selectedRequests->netmask = address;
406e3724c38Smshlyn		else if (!strcasecmp(requests->parameters[index].name, IPCP_PRIMARY_DNS_KEY)) {
407ca43389aSWaldemar Kornewald			selectedRequests->primaryDNS = address;
408e3724c38Smshlyn			if (side == PPP_LOCAL_SIDE)
409ca43389aSWaldemar Kornewald				fRequestPrimaryDNS = true;
410e3724c38Smshlyn		} else if (!strcasecmp(requests->parameters[index].name,
411b8f24e83SWaldemar Kornewald				IPCP_SECONDARY_DNS_KEY)) {
412ca43389aSWaldemar Kornewald			selectedRequests->secondaryDNS = address;
413e3724c38Smshlyn			if (side == PPP_LOCAL_SIDE)
414ca43389aSWaldemar Kornewald				fRequestSecondaryDNS = true;
415ca43389aSWaldemar Kornewald		}
416ca43389aSWaldemar Kornewald	}
417e3724c38Smshlyn
418ca43389aSWaldemar Kornewald	return true;
419ca43389aSWaldemar Kornewald}
420ca43389aSWaldemar Kornewald
421ca43389aSWaldemar Kornewald
422e3724c38Smshlynnet_interface *
423e3724c38Smshlynget_interface_by_name(net_domain *domain, const char *name)
424e3724c38Smshlyn{
425e3724c38Smshlyn	ifreq request;
426e3724c38Smshlyn	memset(&request, 0, sizeof(request));
427e3724c38Smshlyn	size_t size = sizeof(request);
428e3724c38Smshlyn
429e3724c38Smshlyn	strlcpy(request.ifr_name, name, IF_NAMESIZE);
430e3724c38Smshlyn
431e3724c38Smshlyn	if (sDatalinkModule->control(domain, SIOCGIFINDEX, &request, &size) != B_OK) {
432e3724c38Smshlyn		TRACE("sDatalinkModule->control failure\n");
433e3724c38Smshlyn		return NULL;
434e3724c38Smshlyn	}
435e3724c38Smshlyn	return sDatalinkModule->get_interface(domain, request.ifr_index);
436e3724c38Smshlyn}
437e3724c38Smshlyn
438e3724c38Smshlyn
439e3724c38Smshlynstatus_t
440e3724c38Smshlynset_interface_address(net_domain* domain, struct ifaliasreq* inreq)
441e3724c38Smshlyn{
442e3724c38Smshlyn	size_t size = sizeof(struct ifaliasreq);
443e3724c38Smshlyn	return sDatalinkModule->control(domain, B_SOCKET_SET_ALIAS, inreq, &size);
444e3724c38Smshlyn}
445e3724c38Smshlyn
446e3724c38Smshlyn
447ca43389aSWaldemar Kornewaldvoid
448ca43389aSWaldemar KornewaldIPCP::UpdateAddresses()
449ca43389aSWaldemar Kornewald{
450e3724c38Smshlyn	TRACE("%s::%s: entering UpdateAddresses\n", __FILE__, __func__);
4516cfb4dcaSWaldemar Kornewald	RemoveRoutes();
452e3724c38Smshlyn
453e3724c38Smshlyn	if (State() != PPP_OPENED_STATE && !Interface().DoesConnectOnDemand())
454ca43389aSWaldemar Kornewald		return;
455e3724c38Smshlyn
456e3724c38Smshlyn	TRACE("%s::%s: entering ChangeAddress\n", __FILE__, __func__);
457e3724c38Smshlyn	if (sDatalinkModule == NULL) {
458e3724c38Smshlyn		TRACE("%s::%s: some module not found!\n", __FILE__, __func__);
459e3724c38Smshlyn		return;
460e3724c38Smshlyn	}
461e3724c38Smshlyn
462e3724c38Smshlyn
463e3724c38Smshlyn	struct sockaddr newAddr = {6, AF_INET, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
464e3724c38Smshlyn	struct sockaddr netmask = {6, AF_INET, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
465e3724c38Smshlyn	struct sockaddr broadaddr = {6, AF_INET, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
466e3724c38Smshlyn
467e3724c38Smshlyn	if (fLocalRequests.address != INADDR_ANY)
468e3724c38Smshlyn		memcpy(newAddr.sa_data + 2, &fLocalRequests.address, sizeof(in_addr_t));
469e3724c38Smshlyn	else if (fLocalConfiguration.address == INADDR_ANY) {
470e3724c38Smshlyn		in_addr_t inaddrBroadcast = 0x010F0F0F; // was: INADDR_BROADCAST
471e3724c38Smshlyn		memcpy(newAddr.sa_data + 2, &inaddrBroadcast, sizeof(in_addr_t));
472e3724c38Smshlyn	} else
473e3724c38Smshlyn		memcpy(newAddr.sa_data + 2, &fLocalConfiguration.address, sizeof(in_addr_t));
474e3724c38Smshlyn
475e3724c38Smshlyn	struct ifaliasreq inreq;
476e3724c38Smshlyn	memset(&inreq, 0, sizeof(struct ifaliasreq));
477e3724c38Smshlyn	memcpy(inreq.ifra_name, Interface().Name(), IF_NAMESIZE);
478e3724c38Smshlyn	memcpy(&inreq.ifra_addr, &newAddr, sizeof(struct sockaddr));
479e3724c38Smshlyn	memcpy(&inreq.ifra_mask, &netmask, sizeof(struct sockaddr));
480e3724c38Smshlyn	memcpy(&inreq.ifra_broadaddr, &broadaddr, sizeof(struct sockaddr));
481e3724c38Smshlyn	inreq.ifra_index = -1;
482e3724c38Smshlyn		// create a new interface address
483e3724c38Smshlyn		// Is it OK when we already have one?
484e3724c38Smshlyn		// test case:	ifconfig ppp up
485e3724c38Smshlyn		// 		ifconfig ppp down
486e3724c38Smshlyn		// 		ifconfig ppp up
487e3724c38Smshlyn		// 		check if some weird things happen
488e3724c38Smshlyn
489e3724c38Smshlyn	net_domain* domain = sStackModule->get_domain(AF_INET);
490e3724c38Smshlyn	status_t status = set_interface_address(domain, &inreq);
491e3724c38Smshlyn
492e3724c38Smshlyn	if (status != B_OK) {
493e3724c38Smshlyn		TRACE("%s:%s: set_interface_address Fail!!!!\n", __FILE__, __func__);
494e3724c38Smshlyn		return;
495e3724c38Smshlyn	}
496e3724c38Smshlyn	TRACE("%s:%s: set_interface_address fine\n", __FILE__, __func__);
497e3724c38Smshlyn
498e3724c38Smshlyn
499e3724c38Smshlyn	net_interface* pppInterface = get_interface_by_name(domain, Interface().Name());
500e3724c38Smshlyn	if (pppInterface == NULL) {
501e3724c38Smshlyn		TRACE("%s::%s: pppInterface not found!\n", __FILE__, __func__);
502e3724c38Smshlyn		return;
503e3724c38Smshlyn	}
504e3724c38Smshlyn
505e3724c38Smshlyn	net_interface_address* pppInterfaceAddress = NULL;
506e3724c38Smshlyn	while (sDatalinkModule->get_next_interface_address(pppInterface,
507e3724c38Smshlyn				&pppInterfaceAddress)) {
508e3724c38Smshlyn		if (pppInterfaceAddress->domain->family != AF_INET)
509e3724c38Smshlyn			continue;
510e3724c38Smshlyn		break;
511e3724c38Smshlyn	}
512e3724c38Smshlyn
51386c13ddaSWaldemar Kornewald	// add default/subnet route
514e3724c38Smshlyn	if (Side() == PPP_LOCAL_SIDE && pppInterfaceAddress != NULL) {
515e3724c38Smshlyn		struct sockaddr addrGateway = {8, AF_INET, {0x00, 0x00, 0x00, 0x00,
516e3724c38Smshlyn			0x00, 0x00} };
517e3724c38Smshlyn
518e3724c38Smshlyn		// create destination address
519e3724c38Smshlyn		if (fPeerRequests.address != INADDR_ANY)
520e3724c38Smshlyn			memcpy(addrGateway.sa_data + 2, &fPeerRequests.address,
521e3724c38Smshlyn				sizeof(in_addr_t));
522e3724c38Smshlyn		else if (fPeerConfiguration.address == INADDR_ANY) {
523e3724c38Smshlyn			in_addr_t gateway = 0x020F0F0F;
524e3724c38Smshlyn			memcpy(addrGateway.sa_data + 2, &gateway, sizeof(in_addr_t));
525e3724c38Smshlyn				// was: INADDR_BROADCAST
526e3724c38Smshlyn		} else
527e3724c38Smshlyn			memcpy(addrGateway.sa_data + 2, &fPeerConfiguration.address,
528e3724c38Smshlyn				sizeof(in_addr_t));
529e3724c38Smshlyn
530e3724c38Smshlyn		net_route defaultRoute;
531e3724c38Smshlyn		defaultRoute.destination = NULL;
532e3724c38Smshlyn		defaultRoute.mask = NULL;
533e3724c38Smshlyn		defaultRoute.gateway = &addrGateway;
534e3724c38Smshlyn		defaultRoute.flags = RTF_DEFAULT | RTF_GATEWAY;
535e3724c38Smshlyn		defaultRoute.interface_address = pppInterfaceAddress;
536e3724c38Smshlyn			// route->interface_address;
537e3724c38Smshlyn
538e3724c38Smshlyn		status_t status = sDatalinkModule->add_route(domain, &defaultRoute);
539e3724c38Smshlyn		if (status == B_OK)
540e3724c38Smshlyn			dprintf("%s::%s: add route default OK!\n", __FILE__, __func__);
541e3724c38Smshlyn		else
542e3724c38Smshlyn			dprintf("%s::%s: add route default Fail!\n", __FILE__, __func__);
543e3724c38Smshlyn
544e3724c38Smshlyn		sDatalinkModule->put_interface_address(pppInterfaceAddress);
545e3724c38Smshlyn	}
546e3724c38Smshlyn
547e3724c38Smshlyn	if (Side() == PPP_LOCAL_SIDE) {
548e3724c38Smshlyn		int file;
549e3724c38Smshlyn		int primary_dns, secondary_dns;
550e3724c38Smshlyn		char buf[256];
551e3724c38Smshlyn
552e3724c38Smshlyn		file = open(RESOLV_CONF_FILE, O_RDWR);
553e3724c38Smshlyn
554e3724c38Smshlyn		primary_dns = ntohl(fLocalConfiguration.primaryDNS);
555e3724c38Smshlyn		secondary_dns = ntohl(fLocalConfiguration.secondaryDNS);
556e3724c38Smshlyn
557e3724c38Smshlyn		sprintf(buf, "%s\t%d.%d.%d.%d\n%s\t%d.%d.%d.%d\n",
558e3724c38Smshlyn				"nameserver",
559e3724c38Smshlyn				(primary_dns & 0xff000000) >> 24,
560e3724c38Smshlyn				(primary_dns & 0x00ff0000) >> 16,
561e3724c38Smshlyn				(primary_dns & 0x0000ff00) >> 8,
562e3724c38Smshlyn				(primary_dns & 0x000000ff),
563e3724c38Smshlyn				"nameserver",
564e3724c38Smshlyn				(secondary_dns & 0xff000000) >> 24,
565e3724c38Smshlyn				(secondary_dns & 0x00ff0000) >> 16,
566e3724c38Smshlyn				(secondary_dns & 0x0000ff00) >> 8,
567e3724c38Smshlyn				(secondary_dns & 0x000000ff));
568e3724c38Smshlyn
569e3724c38Smshlyn		write(file, buf, strlen(buf));
570e3724c38Smshlyn		close(file);
5711cea3d85SWaldemar Kornewald	}
5726cfb4dcaSWaldemar Kornewald}
5736cfb4dcaSWaldemar Kornewald
5746cfb4dcaSWaldemar Kornewald
5756cfb4dcaSWaldemar Kornewaldvoid
5766cfb4dcaSWaldemar KornewaldIPCP::RemoveRoutes()
5776cfb4dcaSWaldemar Kornewald{
578e3724c38Smshlyn	// note:
579e3724c38Smshlyn	// 	haiku supports multi default route. But for Desktop, ppp is generally
580e3724c38Smshlyn	// 	the only default route. So is it necessary to remove other default
581e3724c38Smshlyn	// 	route?
582e3724c38Smshlyn	TRACE("%s::%s: entering RemoveRoutes!\n", __FILE__, __func__);
583e3724c38Smshlyn
584e3724c38Smshlyn	char *ethernetName = NULL;
585e3724c38Smshlyn	PPPoEDevice* pppoeDevice = (PPPoEDevice *)Interface().Device();
586e3724c38Smshlyn	if (pppoeDevice == NULL)
587e3724c38Smshlyn		return;
588e3724c38Smshlyn	ethernetName = pppoeDevice->EthernetIfnet()->name;
589e3724c38Smshlyn	if (ethernetName == NULL)
590e3724c38Smshlyn		return;
591e3724c38Smshlyn
592e3724c38Smshlyn	net_domain* domain = sStackModule->get_domain(AF_INET);
593e3724c38Smshlyn	net_interface* pppInterface = get_interface_by_name(domain, ethernetName);
594e3724c38Smshlyn
595e3724c38Smshlyn	if (pppInterface == NULL) {
596e3724c38Smshlyn		TRACE("%s::%s: pppInterface not found!\n", __FILE__, __func__);
597e3724c38Smshlyn		return;
598e3724c38Smshlyn	}
599e3724c38Smshlyn
600e3724c38Smshlyn	net_interface_address* pppInterfaceAddress = NULL;
601e3724c38Smshlyn
602e3724c38Smshlyn	while (sDatalinkModule->get_next_interface_address(pppInterface,
603e3724c38Smshlyn				&pppInterfaceAddress)) {
604e3724c38Smshlyn		if (pppInterfaceAddress->domain->family != AF_INET)
605e3724c38Smshlyn			continue;
606e3724c38Smshlyn
607e3724c38Smshlyn		net_route oldDefaultRoute;
608e3724c38Smshlyn		oldDefaultRoute.destination = NULL;
609e3724c38Smshlyn		oldDefaultRoute.mask = NULL;
610e3724c38Smshlyn		oldDefaultRoute.gateway = NULL;
611e3724c38Smshlyn		oldDefaultRoute.flags= RTF_DEFAULT;
612e3724c38Smshlyn		oldDefaultRoute.interface_address = pppInterfaceAddress;
613e3724c38Smshlyn
614e3724c38Smshlyn		status_t status = sDatalinkModule->remove_route(domain, &oldDefaultRoute);
615e3724c38Smshlyn			// current: can not get the system default route so we fake
616e3724c38Smshlyn			// 	    one default route for delete
617e3724c38Smshlyn			// Todo: save the oldDefaultRoute to fDefaultRoute
618e3724c38Smshlyn			// 	 restore the fDefaultRoute when ppp is down
619e3724c38Smshlyn
620e3724c38Smshlyn		sDatalinkModule->put_interface_address(pppInterfaceAddress);
621e3724c38Smshlyn
622e3724c38Smshlyn		if (status == B_OK)
623e3724c38Smshlyn			dprintf("IPCP::RemoveRoutes: remove old default route OK!\n");
624e3724c38Smshlyn		else
625e3724c38Smshlyn			dprintf("IPCP::RemoveRoutes: remove old default route Fail!\n");
626e3724c38Smshlyn
627e3724c38Smshlyn		break;
628e3724c38Smshlyn	}
629e3724c38Smshlyn
630e3724c38Smshlyn	if (fDefaultRoute) {
6316cfb4dcaSWaldemar Kornewald		struct sockaddr_in netmask;
6326cfb4dcaSWaldemar Kornewald		memset(&netmask, 0, sizeof(struct sockaddr_in));
633e3724c38Smshlyn
6346cfb4dcaSWaldemar Kornewald		netmask.sin_family = AF_INET;
6356cfb4dcaSWaldemar Kornewald		netmask.sin_addr.s_addr = fLocalRequests.netmask;
6366cfb4dcaSWaldemar Kornewald		netmask.sin_len = sizeof(struct sockaddr_in);
637e3724c38Smshlyn
638e3724c38Smshlyn		// if (rtrequest(RTM_DELETE, (struct sockaddr*) &netmask,
639e3724c38Smshlyn				// (struct sockaddr*) &fGateway, (struct sockaddr*) &netmask,
640e3724c38Smshlyn				// RTF_UP | RTF_GATEWAY, &fDefaultRoute) != B_OK)
64184b580c4SWaldemar Kornewald			ERROR("IPCP: RemoveRoutes(): could not remove default/subnet route!\n");
642e3724c38Smshlyn
6436cfb4dcaSWaldemar Kornewald		fDefaultRoute = NULL;
6446cfb4dcaSWaldemar Kornewald	}
645ca43389aSWaldemar Kornewald}
646ca43389aSWaldemar Kornewald
647ca43389aSWaldemar Kornewald
648ca43389aSWaldemar Kornewalduint8
649ca43389aSWaldemar KornewaldIPCP::NextID()
650ca43389aSWaldemar Kornewald{
651