ipcp.c revision 25630
1/*
2 *	PPP IP Control Protocol (IPCP) Module
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: ipcp.c,v 1.13 1997/02/22 16:10:20 peter Exp $
21 *
22 *	TODO:
23 *		o More RFC1772 backwoard compatibility
24 */
25#include "fsm.h"
26#include "lcpproto.h"
27#include "lcp.h"
28#include "ipcp.h"
29#include <netdb.h>
30#include <netinet/in_systm.h>
31#include <netinet/ip.h>
32#include <arpa/inet.h>
33#include <sys/socket.h>
34#include "slcompress.h"
35#include "os.h"
36#include "phase.h"
37#include "vars.h"
38#include "alias.h"
39
40extern void PutConfValue();
41extern void Prompt();
42extern struct in_addr ifnetmask;
43
44struct ipcpstate IpcpInfo;
45struct in_range DefMyAddress, DefHisAddress, DefTriggerAddress;
46
47#ifdef MSEXT
48struct in_addr ns_entries[2], nbns_entries[2];
49#endif /* MSEXT */
50
51static void IpcpSendConfigReq __P((struct fsm *));
52static void IpcpSendTerminateAck __P((struct fsm *));
53static void IpcpSendTerminateReq __P((struct fsm *));
54static void IpcpDecodeConfig __P((u_char *, int, int));
55static void IpcpLayerStart __P((struct fsm *));
56static void IpcpLayerFinish __P((struct fsm *));
57static void IpcpLayerUp __P((struct fsm *));
58static void IpcpLayerDown __P((struct fsm *));
59static void IpcpInitRestartCounter __P((struct fsm *));
60
61struct pppTimer IpcpReportTimer;
62
63static int lastInOctets, lastOutOctets;
64
65#define	REJECTED(p, x)	(p->his_reject & (1<<x))
66
67struct fsm IpcpFsm = {
68  "IPCP",
69  PROTO_IPCP,
70  IPCP_MAXCODE,
71  OPEN_ACTIVE,
72  ST_INITIAL,
73  0, 0, 0,
74
75  0,
76  { 0, 0, 0, NULL, NULL, NULL },
77
78  IpcpLayerUp,
79  IpcpLayerDown,
80  IpcpLayerStart,
81  IpcpLayerFinish,
82  IpcpInitRestartCounter,
83  IpcpSendConfigReq,
84  IpcpSendTerminateReq,
85  IpcpSendTerminateAck,
86  IpcpDecodeConfig,
87};
88
89static char *cftypes[] = {
90  "???", "IPADDRS", "COMPPROTO", "IPADDR",
91};
92
93/*
94 * Function called every second. Updates connection period and idle period,
95 * also update LQR information.
96 */
97static void
98IpcpReportFunc()
99{
100  ipConnectSecs++;
101  if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets)
102    ipIdleSecs++;
103  lastInOctets = ipInOctets;
104  lastOutOctets = ipOutOctets;
105  StopTimer(&IpcpReportTimer);
106  IpcpReportTimer.state = TIMER_STOPPED;
107  StartTimer(&IpcpReportTimer);
108}
109
110static void
111IpcpStartReport()
112{
113  ipIdleSecs = ipConnectSecs = 0;
114  StopTimer(&IpcpReportTimer);
115  IpcpReportTimer.state = TIMER_STOPPED;
116  IpcpReportTimer.load = SECTICKS;
117  IpcpReportTimer.func = IpcpReportFunc;
118  StartTimer(&IpcpReportTimer);
119}
120
121int
122ReportIpcpStatus()
123{
124  struct ipcpstate *icp = &IpcpInfo;
125  struct fsm *fp = &IpcpFsm;
126
127  printf("%s [%s]\n", fp->name, StateNames[fp->state]);
128  printf(" his side: %s, %lx\n",
129     inet_ntoa(icp->his_ipaddr), icp->his_compproto);
130  printf(" my  side: %s, %lx\n",
131     inet_ntoa(icp->want_ipaddr), icp->want_compproto);
132  printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs);
133  printf("Defaults:\n");
134  printf(" My Address:  %s/%d\n",
135     inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width);
136  printf(" His Address: %s/%d\n",
137     inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width);
138  printf(" Negotiation: %s/%d\n",
139     inet_ntoa(DefTriggerAddress.ipaddr), DefTriggerAddress.width);
140  return 0;
141}
142
143void
144IpcpDefAddress()
145{
146  struct hostent *hp;
147  char name[200];
148
149  bzero(&DefMyAddress, sizeof(DefMyAddress));
150  bzero(&DefHisAddress, sizeof(DefHisAddress));
151  bzero(&DefTriggerAddress, sizeof(DefTriggerAddress));
152  if (gethostname(name, sizeof(name)) == 0) {
153      hp = gethostbyname(name);
154      if (hp && hp->h_addrtype == AF_INET) {
155	bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length);
156      }
157  }
158}
159
160void
161IpcpInit()
162{
163  struct ipcpstate *icp = &IpcpInfo;
164
165  FsmInit(&IpcpFsm);
166  bzero(icp, sizeof(struct ipcpstate));
167  if ((mode & MODE_DEDICATED) && !dstsystem) {
168    icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0;
169  } else {
170    icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
171    icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
172  }
173
174  /*
175   * Some implementation of PPP are:
176   *  Starting a negotiaion by require sending *special* value as my address,
177   *  even though standard of PPP is defined full negotiation based.
178   *  (e.g. "0.0.0.0" or Not "0.0.0.0")
179   */
180  if ( icp->want_ipaddr.s_addr == 0 ) {
181    icp->want_ipaddr.s_addr = DefTriggerAddress.ipaddr.s_addr;
182  }
183
184  if (Enabled(ConfVjcomp))
185    icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8);
186  else
187    icp->want_compproto = 0;
188  icp->heis1172 = 0;
189  IpcpFsm.maxconfig = 10;
190}
191
192static void
193IpcpInitRestartCounter(fp)
194struct fsm *fp;
195{
196  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
197  fp->restart = 5;
198}
199
200static void
201IpcpSendConfigReq(fp)
202struct fsm *fp;
203{
204  u_char *cp;
205  struct ipcpstate *icp = &IpcpInfo;
206
207  cp = ReqBuff;
208  LogPrintf(LOG_LCP_BIT, "%s: SendConfigReq\n", fp->name);
209  if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR))
210    PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr));
211  if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) {
212    if (icp->heis1172)
213      PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16);
214    else
215      PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto);
216  }
217  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
218}
219
220static void
221IpcpSendTerminateReq(fp)
222struct fsm *fp;
223{
224  /* XXX: No code yet */
225}
226
227static void
228IpcpSendTerminateAck(fp)
229struct fsm *fp;
230{
231  LogPrintf(LOG_LCP_BIT, "  %s: SendTerminateAck\n", fp->name);
232  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
233}
234
235static void
236IpcpLayerStart(fp)
237struct fsm *fp;
238{
239  LogPrintf(LOG_LCP_BIT, "%s: LayerStart.\n", fp->name);
240}
241
242static void
243IpcpLayerFinish(fp)
244struct fsm *fp;
245{
246  LogPrintf(LOG_LCP_BIT, "%s: LayerFinish.\n", fp->name);
247  LcpClose();
248  NewPhase(PHASE_TERMINATE);
249}
250
251static void
252IpcpLayerDown(fp)
253struct fsm *fp;
254{
255  LogPrintf(LOG_LCP_BIT, "%s: LayerDown.\n", fp->name);
256  StopTimer(&IpcpReportTimer);
257}
258
259/*
260 *  Called when IPCP has reached to OPEN state
261 */
262static void
263IpcpLayerUp(fp)
264struct fsm *fp;
265{
266  char tbuff[100];
267
268#ifdef VERBOSE
269  fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state);
270#endif
271  Prompt();
272  LogPrintf(LOG_LCP_BIT, "%s: LayerUp.\n", fp->name);
273  snprintf(tbuff, sizeof(tbuff), "myaddr = %s ",
274    inet_ntoa(IpcpInfo.want_ipaddr));
275  LogPrintf(LOG_LCP_BIT|LOG_LINK_BIT, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
276  if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask) < 0) {
277     printf("unable to set ip address\n");
278     return;
279  }
280  OsLinkup();
281  IpcpStartReport();
282  StartIdleTimer();
283  if (mode & MODE_ALIAS)
284    SetAliasAddress(IpcpInfo.want_ipaddr);
285}
286
287void
288IpcpUp()
289{
290  FsmUp(&IpcpFsm);
291  LogPrintf(LOG_LCP_BIT, "IPCP Up event!!\n");
292}
293
294void
295IpcpOpen()
296{
297  FsmOpen(&IpcpFsm);
298}
299
300static int
301AcceptableAddr(prange, ipaddr)
302struct in_range *prange;
303struct in_addr ipaddr;
304{
305#ifdef DEBUG
306  logprintf("requested = %x ", htonl(ipaddr.s_addr));
307  logprintf("range = %x", htonl(prange->ipaddr.s_addr));
308  logprintf("/%x\n", htonl(prange->mask.s_addr));
309  logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr),
310    htonl(ipaddr.s_addr & prange->mask.s_addr));
311#endif
312  return((prange->ipaddr.s_addr & prange->mask.s_addr) ==
313	(ipaddr.s_addr & prange->mask.s_addr));
314}
315
316static void
317IpcpDecodeConfig(cp, plen, mode)
318u_char *cp;
319int plen;
320int mode;
321{
322  int type, length;
323  u_long *lp, compproto;
324  struct compreq *pcomp;
325  struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
326  char tbuff[100];
327  char tbuff2[100];
328
329  ackp = AckBuff;
330  nakp = NakBuff;
331  rejp = RejBuff;
332
333  while (plen >= sizeof(struct fsmconfig)) {
334    if (plen < 0)
335      break;
336    type = *cp;
337    length = cp[1];
338    if (type <= TY_IPADDR)
339      snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length);
340    else
341      snprintf(tbuff, sizeof(tbuff), " ");
342
343    switch (type) {
344    case TY_IPADDR:		/* RFC1332 */
345      lp = (u_long *)(cp + 2);
346      ipaddr.s_addr = *lp;
347      LogPrintf(LOG_LCP_BIT, "%s %s\n", tbuff, inet_ntoa(ipaddr));
348
349      switch (mode) {
350      case MODE_REQ:
351	if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
352          /*
353           * If destination address is not acceptable, insist to use
354           * what we want to use.
355           */
356	  bcopy(cp, nakp, 2);
357          bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length);
358          nakp += length;
359          break;
360
361	}
362	IpcpInfo.his_ipaddr = ipaddr;
363	bcopy(cp, ackp, length);
364	ackp += length;
365	break;
366      case MODE_NAK:
367	if (AcceptableAddr(&DefMyAddress, ipaddr)) {
368          /*
369           * Use address suggested by peer.
370           */
371	  snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
372	  LogPrintf(LOG_LCP_BIT, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
373	  IpcpInfo.want_ipaddr = ipaddr;
374	}
375	break;
376      case MODE_REJ:
377	IpcpInfo.his_reject |= (1 << type);
378	break;
379      }
380      break;
381    case TY_COMPPROTO:
382      lp = (u_long *)(cp + 2);
383      compproto = htonl(*lp);
384      LogPrintf(LOG_LCP_BIT, "%s %08x\n", tbuff, compproto);
385
386      switch (mode) {
387      case MODE_REQ:
388	if (!Acceptable(ConfVjcomp)) {
389	  bcopy(cp, rejp, length);
390	  rejp += length;
391	} else {
392	  pcomp = (struct compreq *)(cp + 2);
393	  switch (length) {
394	  case 4:	/* RFC1172 */
395	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
396	      logprintf("** Peer is speaking RFC1172 compression protocol **\n");
397	      IpcpInfo.heis1172 = 1;
398	      IpcpInfo.his_compproto = compproto;
399	      bcopy(cp, ackp, length);
400	      ackp += length;
401	    } else {
402	      bcopy(cp, nakp, 2);
403	      pcomp->proto = htons(PROTO_VJCOMP);
404	      bcopy(&pcomp, nakp + 2, 2);
405	      nakp += length;
406	    }
407	    break;
408	  case 6: 	/* RFC1332 */
409	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
410	        && pcomp->slots < MAX_STATES && pcomp->slots > 2) {
411	      IpcpInfo.his_compproto = compproto;
412	      IpcpInfo.heis1172 = 0;
413	      bcopy(cp, ackp, length);
414	      ackp += length;
415	    } else {
416	      bcopy(cp, nakp, 2);
417	      pcomp->proto = htons(PROTO_VJCOMP);
418	      pcomp->slots = MAX_STATES - 1;
419	      pcomp->compcid = 0;
420	      bcopy(&pcomp, nakp + 2, sizeof(pcomp));
421	      nakp += length;
422	    }
423	    break;
424	  default:
425	    bcopy(cp, rejp, length);
426	    rejp += length;
427	    break;
428	  }
429	}
430	break;
431      case MODE_NAK:
432	LogPrintf(LOG_LCP_BIT, "%s changing compproto: %08x --> %08x\n",
433	  tbuff, IpcpInfo.want_compproto, compproto);
434	IpcpInfo.want_compproto = compproto;
435	break;
436      case MODE_REJ:
437	IpcpInfo.his_reject |= (1 << type);
438	break;
439      }
440      break;
441    case TY_IPADDRS:	/* RFC1172 */
442      lp = (u_long *)(cp + 2);
443      ipaddr.s_addr = *lp;
444      lp = (u_long *)(cp + 6);
445      dstipaddr.s_addr = *lp;
446      LogPrintf(LOG_LCP_BIT, "%s %s, ", tbuff, inet_ntoa(ipaddr));
447      LogPrintf(LOG_LCP_BIT, "%s\n", inet_ntoa(dstipaddr));
448
449      switch (mode) {
450      case MODE_REQ:
451	IpcpInfo.his_ipaddr = ipaddr;
452	IpcpInfo.want_ipaddr = dstipaddr;
453	bcopy(cp, ackp, length);
454	ackp += length;
455	break;
456      case MODE_NAK:
457	LogPrintf(LOG_LCP_BIT, "%s changing address: %s ",
458	  tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
459	LogPrintf(LOG_LCP_BIT, "--> %s\n", inet_ntoa(ipaddr));
460	IpcpInfo.want_ipaddr = ipaddr;
461	IpcpInfo.his_ipaddr = dstipaddr;
462	break;
463      case MODE_REJ:
464	IpcpInfo.his_reject |= (1 << type);
465	break;
466      }
467      break;
468
469 /*
470  * MS extensions for MS's PPP
471  */
472
473#ifdef MSEXT
474    case TY_PRIMARY_DNS:   /* MS PPP DNS negotiation hack */
475    case TY_SECONDARY_DNS:
476      if( !Enabled( ConfMSExt ) ) {
477	LogPrintf( LOG_LCP, "MS NS req - rejected - msext disabled\n" );
478	IpcpInfo.my_reject |= ( 1 << type );
479	bcopy(cp, rejp, length);
480	rejp += length;
481	break;
482      }
483      switch( mode ){
484      case MODE_REQ:
485	lp = (u_long *)(cp + 2);
486	dnsstuff.s_addr = *lp;
487	ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS)?1:0)].s_addr;
488	if( dnsstuff.s_addr != ms_info_req.s_addr )
489	{
490	  /*
491	   So the client has got the DNS stuff wrong (first request)
492	   so well tell 'em how it is
493	  */
494	  bcopy( cp, nakp, 2 );  /* copy first two (type/length) */
495	  LogPrintf( LOG_LCP, "MS NS req %d:%s->%s - nak\n",
496		type,
497		inet_ntoa( dnsstuff ),
498		inet_ntoa( ms_info_req ));
499	  bcopy( &ms_info_req, nakp+2, length );
500	  nakp += length;
501	  break;
502	}
503	  /*
504	   Otherwise they have it right (this time) so we send
505	   a ack packet back confirming it... end of story
506	  */
507	LogPrintf( LOG_LCP, "MS NS req %d:%s ok - ack\n",
508		type,
509		inet_ntoa( ms_info_req ));
510	bcopy( cp, ackp, length );
511	ackp += length;
512	break;
513      case MODE_NAK: /* what does this mean?? */
514	LogPrintf(LOG_LCP, "MS NS req %d - NAK??\n", type );
515	break;
516      case MODE_REJ: /* confused?? me to :) */
517	LogPrintf(LOG_LCP, "MS NS req %d - REJ??\n", type );
518	break;
519      }
520      break;
521
522    case TY_PRIMARY_NBNS:   /* MS PPP NetBIOS nameserver hack */
523    case TY_SECONDARY_NBNS:
524    if( !Enabled( ConfMSExt ) ) {
525      LogPrintf( LOG_LCP, "MS NBNS req - rejected - msext disabled\n" );
526      IpcpInfo.my_reject |= ( 1 << type );
527      bcopy( cp, rejp, length );
528      rejp += length;
529      break;
530    }
531      switch( mode ){
532      case MODE_REQ:
533	lp = (u_long *)(cp + 2);
534	dnsstuff.s_addr = *lp;
535	ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS)?1:0)].s_addr;
536	if( dnsstuff.s_addr != ms_info_req.s_addr )
537	{
538	  bcopy( cp, nakp, 2 );
539	  bcopy( &ms_info_req.s_addr , nakp+2, length );
540	  LogPrintf( LOG_LCP, "MS NBNS req %d:%s->%s - nak\n",
541		type,
542		inet_ntoa( dnsstuff ),
543		inet_ntoa( ms_info_req ));
544	  nakp += length;
545	  break;
546	}
547	LogPrintf( LOG_LCP, "MS NBNS req %d:%s ok - ack\n",
548		type,
549		inet_ntoa( ms_info_req ));
550	bcopy( cp, ackp, length );
551	ackp += length;
552	break;
553      case MODE_NAK:
554	LogPrintf( LOG_LCP, "MS NBNS req %d - NAK??\n", type );
555	break;
556      case MODE_REJ:
557	LogPrintf( LOG_LCP, "MS NBNS req %d - REJ??\n", type );
558	break;
559      }
560      break;
561
562#endif /* MSEXT */
563
564    default:
565      IpcpInfo.my_reject |= (1 << type);
566      bcopy(cp, rejp, length);
567      rejp += length;
568      break;
569    }
570    plen -= length;
571    cp += length;
572  }
573}
574
575void
576IpcpInput(struct mbuf *bp)
577{
578  FsmInput(&IpcpFsm, bp);
579}
580