ipcp.c revision 7001
1100206Sdd/*
2100206Sdd *	PPP IP Control Protocol (IPCP) Module
3100206Sdd *
4100206Sdd *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5100206Sdd *
6100206Sdd *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7100206Sdd *
8100206Sdd * Redistribution and use in source and binary forms are permitted
9100206Sdd * provided that the above copyright notice and this paragraph are
10100206Sdd * duplicated in all such forms and that any documentation,
11100206Sdd * advertising materials, and other materials related to such
12100206Sdd * distribution and use acknowledge that the software was developed
13100206Sdd * by the Internet Initiative Japan, Inc.  The name of the
14100206Sdd * IIJ may not be used to endorse or promote products derived
15100206Sdd * from this software without specific prior written permission.
16100206Sdd * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17100206Sdd * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18100206Sdd * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19100206Sdd *
20100206Sdd * $Id: ipcp.c,v 1.2 1995/02/26 12:17:33 amurai Exp $
21100206Sdd *
22100206Sdd *	TODO:
23100206Sdd *		o More RFC1772 backwoard compatibility
24100206Sdd */
25100206Sdd#include "fsm.h"
26100206Sdd#include "lcpproto.h"
27100206Sdd#include "lcp.h"
28100206Sdd#include "ipcp.h"
29100206Sdd#include <netdb.h>
30100206Sdd#include <netinet/in_systm.h>
31100206Sdd#include <netinet/ip.h>
32100206Sdd#include <arpa/inet.h>
33100206Sdd#include <sys/socket.h>
34100206Sdd#include "slcompress.h"
35100206Sdd#include "os.h"
36100206Sdd#include "phase.h"
37100206Sdd#include "vars.h"
38100799Sdd
39100206Sddextern void PutConfValue();
40100206Sddextern void Prompt();
41100206Sddextern struct in_addr ifnetmask;
42100206Sdd
43100206Sddstruct ipcpstate IpcpInfo;
44100206Sddstruct in_range DefMyAddress, DefHisAddress;
45100206Sdd
46100206Sddstatic void IpcpSendConfigReq __P((struct fsm *));
47100206Sddstatic void IpcpSendTerminateAck __P((struct fsm *));
48100206Sddstatic void IpcpSendTerminateReq __P((struct fsm *));
49100206Sddstatic void IpcpDecodeConfig __P((u_char *, int, int));
50100803Sddstatic void IpcpLayerStart __P((struct fsm *));
51100799Sddstatic void IpcpLayerFinish __P((struct fsm *));
52100799Sddstatic void IpcpLayerUp __P((struct fsm *));
53100206Sddstatic void IpcpLayerDown __P((struct fsm *));
54100206Sddstatic void IpcpInitRestartCounter __P((struct fsm *));
55100206Sdd
56100206Sddstruct pppTimer IpcpReportTimer;
57100206Sdd
58100206Sddstatic int lastInOctets, lastOutOctets;
59100206Sdd
60100206Sdd#define	REJECTED(p, x)	(p->his_reject & (1<<x))
61100206Sdd
62100206Sddstruct fsm IpcpFsm = {
63100206Sdd  "IPCP",
64100206Sdd  PROTO_IPCP,
65100206Sdd  IPCP_MAXCODE,
66100206Sdd  OPEN_ACTIVE,
67100206Sdd  ST_INITIAL,
68100206Sdd  0, 0, 0,
69100206Sdd
70100206Sdd  0,
71100206Sdd  { 0, 0, 0, NULL, NULL, NULL },
72100206Sdd
73100206Sdd  IpcpLayerUp,
74100206Sdd  IpcpLayerDown,
75100206Sdd  IpcpLayerStart,
76100206Sdd  IpcpLayerFinish,
77100206Sdd  IpcpInitRestartCounter,
78100206Sdd  IpcpSendConfigReq,
79100206Sdd  IpcpSendTerminateReq,
80100206Sdd  IpcpSendTerminateAck,
81100206Sdd  IpcpDecodeConfig,
82100206Sdd};
83100206Sdd
84100206Sddstatic char *cftypes[] = {
85124830Sgrehan  "???", "IPADDRS", "COMPPROTO", "IPADDR",
86100206Sdd};
87100206Sdd
88100206Sdd/*
89100206Sdd * Function called every second. Updates connection period and idle period,
90100206Sdd * also update LQR information.
91100206Sdd */
92100206Sddstatic void
93100206SddIpcpReportFunc()
94100206Sdd{
95100206Sdd  ipConnectSecs++;
96100206Sdd  if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets)
97100206Sdd    ipIdleSecs++;
98100206Sdd  lastInOctets = ipInOctets;
99100206Sdd  lastOutOctets = ipOutOctets;
100100206Sdd  StopTimer(&IpcpReportTimer);
101100206Sdd  IpcpReportTimer.state = TIMER_STOPPED;
102100206Sdd  StartTimer(&IpcpReportTimer);
103100206Sdd}
104100206Sdd
105100206Sddstatic void
106100206SddIpcpStartReport()
107100206Sdd{
108100206Sdd  ipIdleSecs = ipConnectSecs = 0;
109100206Sdd  StopTimer(&IpcpReportTimer);
110100206Sdd  IpcpReportTimer.state = TIMER_STOPPED;
111100206Sdd  IpcpReportTimer.load = SECTICKS;
112100206Sdd  IpcpReportTimer.func = IpcpReportFunc;
113100206Sdd  StartTimer(&IpcpReportTimer);
114100206Sdd}
115100206Sdd
116100799Sddvoid
117100799SddReportIpcpStatus()
118100799Sdd{
119100799Sdd  struct ipcpstate *icp = &IpcpInfo;
120100799Sdd  struct fsm *fp = &IpcpFsm;
121100799Sdd
122100799Sdd  printf("%s [%s]\n", fp->name, StateNames[fp->state]);
123100799Sdd  printf(" his side: %s, %x\n",
124100206Sdd     inet_ntoa(icp->his_ipaddr), icp->his_compproto);
125100206Sdd  printf(" my  side: %s, %x\n",
126100206Sdd     inet_ntoa(icp->want_ipaddr), icp->want_compproto);
127100206Sdd  printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs);
128100206Sdd  printf("Defaults:  My Address: %s/%d  ",
129100206Sdd     inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width);
130100206Sdd  printf("His Address: %s/%d\n",
131100206Sdd     inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width);
132100206Sdd}
133100206Sdd
134100206Sddvoid
135100206SddIpcpDefAddress()
136100206Sdd{
137100206Sdd  struct hostent *hp;
138100799Sdd  char name[200];
139100799Sdd
140100799Sdd  bzero(&DefMyAddress, sizeof(DefMyAddress));
141100799Sdd  bzero(&DefHisAddress, sizeof(DefHisAddress));
142100799Sdd  if (gethostname(name, sizeof(name)) == 0) {
143100799Sdd      hp = gethostbyname(name);
144100799Sdd      if (hp && hp->h_addrtype == AF_INET) {
145100799Sdd	bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length);
146100206Sdd      }
147100206Sdd  }
148100206Sdd}
149100206Sdd
150100206Sddvoid
151100206SddIpcpInit()
152100206Sdd{
153100206Sdd  struct ipcpstate *icp = &IpcpInfo;
154100206Sdd
155100206Sdd  FsmInit(&IpcpFsm);
156100206Sdd  bzero(icp, sizeof(struct ipcpstate));
157100206Sdd  if ((mode & MODE_DEDICATED) && !dstsystem) {
158100206Sdd    icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0;
159100206Sdd  } else {
160100206Sdd    icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
161100206Sdd    icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
162100206Sdd  }
163100206Sdd  if (icp->want_ipaddr.s_addr == 0)
164100206Sdd    icp->want_ipaddr.s_addr = htonl(0xc0000001);
165100206Sdd  if (Enabled(ConfVjcomp))
166100206Sdd    icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8);
167100206Sdd  else
168100206Sdd    icp->want_compproto = 0;
169100206Sdd  icp->heis1172 = 0;
170100206Sdd  IpcpFsm.maxconfig = 10;
171100206Sdd}
172100206Sdd
173100206Sddstatic void
174100206SddIpcpInitRestartCounter(fp)
175100206Sddstruct fsm *fp;
176100206Sdd{
177100206Sdd  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
178100206Sdd  fp->restart = 5;
179100206Sdd}
180100206Sdd
181100206Sddstatic void
182100206SddIpcpSendConfigReq(fp)
183100206Sddstruct fsm *fp;
184100206Sdd{
185100206Sdd  u_char *cp;
186100206Sdd  struct ipcpstate *icp = &IpcpInfo;
187100206Sdd
188100206Sdd  cp = ReqBuff;
189100206Sdd  LogPrintf(LOG_LCP, "%s: SendConfigReq\n", fp->name);
190100206Sdd  if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR))
191100206Sdd    PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr));
192100206Sdd  if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) {
193100206Sdd    if (icp->heis1172)
194100206Sdd      PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16);
195100206Sdd    else
196100206Sdd      PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto);
197100206Sdd  }
198100206Sdd  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
199100206Sdd}
200100206Sdd
201100206Sddstatic void
202100206SddIpcpSendTerminateReq(fp)
203100206Sddstruct fsm *fp;
204100206Sdd{
205100206Sdd  /* XXX: No code yet */
206100206Sdd}
207100206Sdd
208100206Sddstatic void
209100206SddIpcpSendTerminateAck(fp)
210100206Sddstruct fsm *fp;
211100206Sdd{
212100206Sdd  LogPrintf(LOG_LCP, "  %s: SendTerminateAck\n", fp->name);
213100206Sdd  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
214100206Sdd}
215100206Sdd
216100206Sddstatic void
217100206SddIpcpLayerStart(fp)
218100206Sddstruct fsm *fp;
219100206Sdd{
220100206Sdd  LogPrintf(LOG_LCP, "%s: LayerStart.\n", fp->name);
221100206Sdd}
222100206Sdd
223100206Sddstatic void
224100206SddIpcpLayerFinish(fp)
225100206Sddstruct fsm *fp;
226100206Sdd{
227100206Sdd  LogPrintf(LOG_LCP, "%s: LayerFinish.\n", fp->name);
228100206Sdd  LcpClose();
229100805Sdd  NewPhase(PHASE_TERMINATE);
230100206Sdd}
231100206Sdd
232100206Sddstatic void
233100206SddIpcpLayerDown(fp)
234100206Sddstruct fsm *fp;
235100206Sdd{
236100206Sdd  LogPrintf(LOG_LCP, "%s: LayerDown.\n", fp->name);
237100206Sdd  StopTimer(&IpcpReportTimer);
238100206Sdd}
239100206Sdd
240100206Sdd/*
241100206Sdd *  Called when IPCP has reached to OPEN state
242100206Sdd */
243100206Sddstatic void
244100206SddIpcpLayerUp(fp)
245100206Sddstruct fsm *fp;
246100206Sdd{
247100206Sdd  char tbuff[100];
248100206Sdd
249100206Sdd#ifdef VERBOSE
250100206Sdd  fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state);
251100206Sdd#endif
252100206Sdd  Prompt(1);
253100206Sdd  LogPrintf(LOG_LCP, "%s: LayerUp.\n", fp->name);
254100206Sdd  sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr));
255100206Sdd  LogPrintf(LOG_LCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
256100206Sdd  OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
257100206Sdd  OsLinkup();
258100206Sdd  IpcpStartReport();
259100206Sdd  StartIdleTimer();
260100206Sdd}
261100206Sdd
262100206Sddvoid
263100206SddIpcpUp()
264100799Sdd{
265100799Sdd  FsmUp(&IpcpFsm);
266100799Sdd  LogPrintf(LOG_LCP, "IPCP Up event!!\n");
267100799Sdd}
268100799Sdd
269100799Sddvoid
270100799SddIpcpOpen()
271100803Sdd{
272100799Sdd  FsmOpen(&IpcpFsm);
273100799Sdd}
274100799Sdd
275100799Sddstatic int
276100799SddAcceptableAddr(prange, ipaddr)
277100799Sddstruct in_range *prange;
278100799Sddstruct in_addr ipaddr;
279100799Sdd{
280100803Sdd#ifdef DEBUG
281100799Sdd  logprintf("requested = %x ", htonl(ipaddr.s_addr));
282100799Sdd  logprintf("range = %x", htonl(prange->ipaddr.s_addr));
283100799Sdd  logprintf("/%x\n", htonl(prange->mask.s_addr));
284100799Sdd  logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr),
285100799Sdd    htonl(ipaddr.s_addr & prange->mask.s_addr));
286100799Sdd#endif
287100799Sdd  return((prange->ipaddr.s_addr & prange->mask.s_addr) ==
288100799Sdd	(ipaddr.s_addr & prange->mask.s_addr));
289100799Sdd}
290100799Sdd
291100799Sddstatic void
292100799SddIpcpDecodeConfig(cp, plen, mode)
293100799Sddu_char *cp;
294100799Sddint plen;
295100799Sddint mode;
296100799Sdd{
297100799Sdd  int type, length;
298100799Sdd  u_long *lp, compproto;
299100799Sdd  struct compreq *pcomp;
300100799Sdd  struct in_addr ipaddr, dstipaddr;
301100799Sdd  char tbuff[100];
302100799Sdd
303100799Sdd  ackp = AckBuff;
304100799Sdd  nakp = NakBuff;
305100799Sdd  rejp = RejBuff;
306100799Sdd
307100206Sdd  while (plen >= sizeof(struct fsmconfig)) {
308100206Sdd    if (plen < 0)
309100206Sdd      break;
310100206Sdd    type = *cp;
311100206Sdd    length = cp[1];
312100206Sdd    if (type <= TY_IPADDR)
313100206Sdd      sprintf(tbuff, " %s[%d] ", cftypes[type], length);
314100206Sdd    else
315100206Sdd      sprintf(tbuff, " ");
316100206Sdd
317100206Sdd    switch (type) {
318100206Sdd    case TY_IPADDR:		/* RFC1332 */
319100206Sdd      lp = (u_long *)(cp + 2);
320100206Sdd      ipaddr.s_addr = *lp;
321100206Sdd      LogPrintf(LOG_LCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
322100206Sdd
323100206Sdd      switch (mode) {
324100206Sdd      case MODE_REQ:
325100206Sdd	if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
326100206Sdd          /*
327100206Sdd           * If destination address is not acceptable, insist to use
328100206Sdd           * what we want to use.
329100206Sdd           */
330100206Sdd	  bcopy(cp, nakp, 2);
331100206Sdd          bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length);
332100206Sdd          nakp += length;
333100206Sdd          break;
334100206Sdd
335100206Sdd	}
336100206Sdd	IpcpInfo.his_ipaddr = ipaddr;
337100206Sdd	bcopy(cp, ackp, length);
338100206Sdd	ackp += length;
339100206Sdd	break;
340100206Sdd      case MODE_NAK:
341100206Sdd	if (AcceptableAddr(&DefMyAddress, ipaddr)) {
342100206Sdd          /*
343100206Sdd           * Use address suggested by peer.
344100206Sdd           */
345100206Sdd	  sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
346100206Sdd	  LogPrintf(LOG_LCP, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr));
347100206Sdd	  IpcpInfo.want_ipaddr = ipaddr;
348100206Sdd	}
349100206Sdd	break;
350100206Sdd      case MODE_REJ:
351100206Sdd	IpcpInfo.his_reject |= (1 << type);
352100206Sdd	break;
353100206Sdd      }
354100206Sdd      break;
355100206Sdd    case TY_COMPPROTO:
356100206Sdd      lp = (u_long *)(cp + 2);
357100206Sdd      compproto = htonl(*lp);
358100206Sdd      LogPrintf(LOG_LCP, "%s %08x\n", tbuff, compproto);
359100206Sdd
360100206Sdd      switch (mode) {
361100206Sdd      case MODE_REQ:
362100206Sdd	if (!Acceptable(ConfVjcomp)) {
363100206Sdd	  bcopy(cp, rejp, length);
364100206Sdd	  rejp += length;
365100206Sdd	} else {
366100206Sdd	  pcomp = (struct compreq *)(cp + 2);
367100206Sdd	  switch (length) {
368100206Sdd	  case 4:	/* RFC1172 */
369100206Sdd	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
370100206Sdd	      logprintf("** Peer is speaking RFC1172 compression protocol **\n");
371100206Sdd	      IpcpInfo.heis1172 = 1;
372100206Sdd	      IpcpInfo.his_compproto = compproto;
373100206Sdd	      bcopy(cp, ackp, length);
374100206Sdd	      ackp += length;
375100206Sdd	    } else {
376100206Sdd	      bcopy(cp, nakp, 2);
377100206Sdd	      pcomp->proto = htons(PROTO_VJCOMP);
378100206Sdd	      bcopy(&pcomp, nakp + 2, 2);
379100206Sdd	      nakp += length;
380100206Sdd	    }
381100206Sdd	    break;
382100206Sdd	  case 6: 	/* RFC1332 */
383100206Sdd	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
384100206Sdd	        && pcomp->slots < MAX_STATES && pcomp->slots > 2) {
385100206Sdd	      IpcpInfo.his_compproto = compproto;
386100206Sdd	      IpcpInfo.heis1172 = 0;
387100206Sdd	      bcopy(cp, ackp, length);
388100206Sdd	      ackp += length;
389100206Sdd	    } else {
390100206Sdd	      bcopy(cp, nakp, 2);
391100206Sdd	      pcomp->proto = htons(PROTO_VJCOMP);
392100206Sdd	      pcomp->slots = MAX_STATES - 1;
393100206Sdd	      pcomp->compcid = 0;
394100206Sdd	      bcopy(&pcomp, nakp + 2, sizeof(pcomp));
395100206Sdd	      nakp += length;
396100206Sdd	    }
397100206Sdd	    break;
398100206Sdd	  default:
399100206Sdd	    bcopy(cp, rejp, length);
400100206Sdd	    rejp += length;
401100206Sdd	    break;
402100206Sdd	  }
403100206Sdd	}
404100206Sdd	break;
405100206Sdd      case MODE_NAK:
406100206Sdd	LogPrintf(LOG_LCP, "%s changing compproto: %08x --> %08x\n",
407100206Sdd	  tbuff, IpcpInfo.want_compproto, compproto);
408100206Sdd	IpcpInfo.want_compproto = compproto;
409100206Sdd	break;
410100206Sdd      case MODE_REJ:
411100206Sdd	IpcpInfo.his_reject |= (1 << type);
412100206Sdd	break;
413100206Sdd      }
414100206Sdd      break;
415100206Sdd    case TY_IPADDRS:	/* RFC1172 */
416100206Sdd      lp = (u_long *)(cp + 2);
417100206Sdd      ipaddr.s_addr = *lp;
418100206Sdd      lp = (u_long *)(cp + 6);
419100206Sdd      dstipaddr.s_addr = *lp;
420100206Sdd      LogPrintf(LOG_LCP, "%s %s, ", tbuff, inet_ntoa(ipaddr));
421100206Sdd      LogPrintf(LOG_LCP, "%s\n", inet_ntoa(dstipaddr));
422100206Sdd
423100206Sdd      switch (mode) {
424100206Sdd      case MODE_REQ:
425100206Sdd	IpcpInfo.his_ipaddr = ipaddr;
426100206Sdd	IpcpInfo.want_ipaddr = dstipaddr;
427100206Sdd	bcopy(cp, ackp, length);
428100206Sdd	ackp += length;
429100206Sdd	break;
430100206Sdd      case MODE_NAK:
431100206Sdd	LogPrintf(LOG_LCP, "%s changing address: %s ",
432100206Sdd	  tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
433100206Sdd	LogPrintf(LOG_LCP, "--> %s\n", inet_ntoa(ipaddr));
434100206Sdd	IpcpInfo.want_ipaddr = ipaddr;
435100206Sdd	IpcpInfo.his_ipaddr = dstipaddr;
436100206Sdd	break;
437100206Sdd      case MODE_REJ:
438100206Sdd	IpcpInfo.his_reject |= (1 << type);
439100206Sdd	break;
440100206Sdd      }
441100206Sdd      break;
442100206Sdd    default:
443100206Sdd      IpcpInfo.my_reject |= (1 << type);
444100206Sdd      bcopy(cp, rejp, length);
445100206Sdd      rejp += length;
446100206Sdd      break;
447100206Sdd    }
448100206Sdd    plen -= length;
449100206Sdd    cp += length;
450100206Sdd  }
451100206Sdd}
452100206Sdd
453100206Sddvoid
454100206SddIpcpInput(struct mbuf *bp)
455100206Sdd{
456100206Sdd  FsmInput(&IpcpFsm, bp);
457100206Sdd}
458100206Sdd