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