ipcp.c revision 26098
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.18 1997/05/23 04:54:02 brian 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 <alias.h>
35#include "slcompress.h"
36#include "os.h"
37#include "phase.h"
38#include "vars.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 1;
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  reconnect(RECON_FALSE);
248  LcpClose();
249  NewPhase(PHASE_TERMINATE);
250}
251
252static void
253IpcpLayerDown(fp)
254struct fsm *fp;
255{
256  LogPrintf(LOG_LCP_BIT, "%s: LayerDown.\n", fp->name);
257  StopTimer(&IpcpReportTimer);
258}
259
260/*
261 *  Called when IPCP has reached to OPEN state
262 */
263static void
264IpcpLayerUp(fp)
265struct fsm *fp;
266{
267  char tbuff[100];
268
269#ifdef VERBOSE
270  fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state);
271#endif
272  Prompt();
273  LogPrintf(LOG_LCP_BIT, "%s: LayerUp.\n", fp->name);
274  snprintf(tbuff, sizeof(tbuff), "myaddr = %s ",
275    inet_ntoa(IpcpInfo.want_ipaddr));
276  LogPrintf(LOG_LCP_BIT|LOG_LINK_BIT, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
277  if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask) < 0) {
278     printf("unable to set ip address\n");
279     return;
280  }
281  OsLinkup();
282  IpcpStartReport();
283  StartIdleTimer();
284  if (mode & MODE_ALIAS)
285    SetPacketAliasAddress(IpcpInfo.want_ipaddr);
286}
287
288void
289IpcpUp()
290{
291  FsmUp(&IpcpFsm);
292  LogPrintf(LOG_LCP_BIT, "IPCP Up event!!\n");
293}
294
295void
296IpcpOpen()
297{
298  FsmOpen(&IpcpFsm);
299}
300
301static int
302AcceptableAddr(prange, ipaddr)
303struct in_range *prange;
304struct in_addr ipaddr;
305{
306#ifdef DEBUG
307  logprintf("requested = %x ", htonl(ipaddr.s_addr));
308  logprintf("range = %x", htonl(prange->ipaddr.s_addr));
309  logprintf("/%x\n", htonl(prange->mask.s_addr));
310  logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr),
311    htonl(ipaddr.s_addr & prange->mask.s_addr));
312#endif
313  return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
314	(ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
315}
316
317static void
318IpcpDecodeConfig(cp, plen, mode)
319u_char *cp;
320int plen;
321int mode;
322{
323  int type, length;
324  u_long *lp, compproto;
325  struct compreq *pcomp;
326  struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
327  char tbuff[100];
328  char tbuff2[100];
329
330  ackp = AckBuff;
331  nakp = NakBuff;
332  rejp = RejBuff;
333
334  while (plen >= sizeof(struct fsmconfig)) {
335    if (plen < 0)
336      break;
337    type = *cp;
338    length = cp[1];
339    if (type <= TY_IPADDR)
340      snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length);
341    else
342      snprintf(tbuff, sizeof(tbuff), " ");
343
344    switch (type) {
345    case TY_IPADDR:		/* RFC1332 */
346      lp = (u_long *)(cp + 2);
347      ipaddr.s_addr = *lp;
348      LogPrintf(LOG_LCP_BIT, "%s %s\n", tbuff, inet_ntoa(ipaddr));
349
350      switch (mode) {
351      case MODE_REQ:
352	if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
353          /*
354           * If destination address is not acceptable, insist to use
355           * what we want to use.
356           */
357	  bcopy(cp, nakp, 2);
358          bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length);
359          nakp += length;
360          break;
361
362	}
363	IpcpInfo.his_ipaddr = ipaddr;
364	bcopy(cp, ackp, length);
365	ackp += length;
366	break;
367      case MODE_NAK:
368	if (AcceptableAddr(&DefMyAddress, ipaddr)) {
369          /*
370           * Use address suggested by peer.
371           */
372	  snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
373	  LogPrintf(LOG_LCP_BIT, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
374	  IpcpInfo.want_ipaddr = ipaddr;
375	}
376	break;
377      case MODE_REJ:
378	IpcpInfo.his_reject |= (1 << type);
379	break;
380      }
381      break;
382    case TY_COMPPROTO:
383      lp = (u_long *)(cp + 2);
384      compproto = htonl(*lp);
385      LogPrintf(LOG_LCP_BIT, "%s %08x\n", tbuff, compproto);
386
387      switch (mode) {
388      case MODE_REQ:
389	if (!Acceptable(ConfVjcomp)) {
390	  bcopy(cp, rejp, length);
391	  rejp += length;
392	} else {
393	  pcomp = (struct compreq *)(cp + 2);
394	  switch (length) {
395	  case 4:	/* RFC1172 */
396	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
397	      logprintf("** Peer is speaking RFC1172 compression protocol **\n");
398	      IpcpInfo.heis1172 = 1;
399	      IpcpInfo.his_compproto = compproto;
400	      bcopy(cp, ackp, length);
401	      ackp += length;
402	    } else {
403	      bcopy(cp, nakp, 2);
404	      pcomp->proto = htons(PROTO_VJCOMP);
405	      bcopy(&pcomp, nakp + 2, 2);
406	      nakp += length;
407	    }
408	    break;
409	  case 6: 	/* RFC1332 */
410	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
411	        && pcomp->slots < MAX_STATES && pcomp->slots > 2) {
412	      IpcpInfo.his_compproto = compproto;
413	      IpcpInfo.heis1172 = 0;
414	      bcopy(cp, ackp, length);
415	      ackp += length;
416	    } else {
417	      bcopy(cp, nakp, 2);
418	      pcomp->proto = htons(PROTO_VJCOMP);
419	      pcomp->slots = MAX_STATES - 1;
420	      pcomp->compcid = 0;
421	      bcopy(&pcomp, nakp + 2, sizeof(pcomp));
422	      nakp += length;
423	    }
424	    break;
425	  default:
426	    bcopy(cp, rejp, length);
427	    rejp += length;
428	    break;
429	  }
430	}
431	break;
432      case MODE_NAK:
433	LogPrintf(LOG_LCP_BIT, "%s changing compproto: %08x --> %08x\n",
434	  tbuff, IpcpInfo.want_compproto, compproto);
435	IpcpInfo.want_compproto = compproto;
436	break;
437      case MODE_REJ:
438	IpcpInfo.his_reject |= (1 << type);
439	break;
440      }
441      break;
442    case TY_IPADDRS:	/* RFC1172 */
443      lp = (u_long *)(cp + 2);
444      ipaddr.s_addr = *lp;
445      lp = (u_long *)(cp + 6);
446      dstipaddr.s_addr = *lp;
447      LogPrintf(LOG_LCP_BIT, "%s %s, ", tbuff, inet_ntoa(ipaddr));
448      LogPrintf(LOG_LCP_BIT, "%s\n", inet_ntoa(dstipaddr));
449
450      switch (mode) {
451      case MODE_REQ:
452	IpcpInfo.his_ipaddr = ipaddr;
453	IpcpInfo.want_ipaddr = dstipaddr;
454	bcopy(cp, ackp, length);
455	ackp += length;
456	break;
457      case MODE_NAK:
458	LogPrintf(LOG_LCP_BIT, "%s changing address: %s ",
459	  tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
460	LogPrintf(LOG_LCP_BIT, "--> %s\n", inet_ntoa(ipaddr));
461	IpcpInfo.want_ipaddr = ipaddr;
462	IpcpInfo.his_ipaddr = dstipaddr;
463	break;
464      case MODE_REJ:
465	IpcpInfo.his_reject |= (1 << type);
466	break;
467      }
468      break;
469
470 /*
471  * MS extensions for MS's PPP
472  */
473
474#ifdef MSEXT
475    case TY_PRIMARY_DNS:   /* MS PPP DNS negotiation hack */
476    case TY_SECONDARY_DNS:
477      if( !Enabled( ConfMSExt ) ) {
478	LogPrintf( LOG_LCP, "MS NS req - rejected - msext disabled\n" );
479	IpcpInfo.my_reject |= ( 1 << type );
480	bcopy(cp, rejp, length);
481	rejp += length;
482	break;
483      }
484      switch( mode ){
485      case MODE_REQ:
486	lp = (u_long *)(cp + 2);
487	dnsstuff.s_addr = *lp;
488	ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS)?1:0)].s_addr;
489	if( dnsstuff.s_addr != ms_info_req.s_addr )
490	{
491	  /*
492	   So the client has got the DNS stuff wrong (first request)
493	   so well tell 'em how it is
494	  */
495	  bcopy( cp, nakp, 2 );  /* copy first two (type/length) */
496	  LogPrintf( LOG_LCP, "MS NS req %d:%s->%s - nak\n",
497		type,
498		inet_ntoa( dnsstuff ),
499		inet_ntoa( ms_info_req ));
500	  bcopy( &ms_info_req, nakp+2, length );
501	  nakp += length;
502	  break;
503	}
504	  /*
505	   Otherwise they have it right (this time) so we send
506	   a ack packet back confirming it... end of story
507	  */
508	LogPrintf( LOG_LCP, "MS NS req %d:%s ok - ack\n",
509		type,
510		inet_ntoa( ms_info_req ));
511	bcopy( cp, ackp, length );
512	ackp += length;
513	break;
514      case MODE_NAK: /* what does this mean?? */
515	LogPrintf(LOG_LCP, "MS NS req %d - NAK??\n", type );
516	break;
517      case MODE_REJ: /* confused?? me to :) */
518	LogPrintf(LOG_LCP, "MS NS req %d - REJ??\n", type );
519	break;
520      }
521      break;
522
523    case TY_PRIMARY_NBNS:   /* MS PPP NetBIOS nameserver hack */
524    case TY_SECONDARY_NBNS:
525    if( !Enabled( ConfMSExt ) ) {
526      LogPrintf( LOG_LCP, "MS NBNS req - rejected - msext disabled\n" );
527      IpcpInfo.my_reject |= ( 1 << type );
528      bcopy( cp, rejp, length );
529      rejp += length;
530      break;
531    }
532      switch( mode ){
533      case MODE_REQ:
534	lp = (u_long *)(cp + 2);
535	dnsstuff.s_addr = *lp;
536	ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS)?1:0)].s_addr;
537	if( dnsstuff.s_addr != ms_info_req.s_addr )
538	{
539	  bcopy( cp, nakp, 2 );
540	  bcopy( &ms_info_req.s_addr , nakp+2, length );
541	  LogPrintf( LOG_LCP, "MS NBNS req %d:%s->%s - nak\n",
542		type,
543		inet_ntoa( dnsstuff ),
544		inet_ntoa( ms_info_req ));
545	  nakp += length;
546	  break;
547	}
548	LogPrintf( LOG_LCP, "MS NBNS req %d:%s ok - ack\n",
549		type,
550		inet_ntoa( ms_info_req ));
551	bcopy( cp, ackp, length );
552	ackp += length;
553	break;
554      case MODE_NAK:
555	LogPrintf( LOG_LCP, "MS NBNS req %d - NAK??\n", type );
556	break;
557      case MODE_REJ:
558	LogPrintf( LOG_LCP, "MS NBNS req %d - REJ??\n", type );
559	break;
560      }
561      break;
562
563#endif /* MSEXT */
564
565    default:
566      IpcpInfo.my_reject |= (1 << type);
567      bcopy(cp, rejp, length);
568      rejp += length;
569      break;
570    }
571    plen -= length;
572    cp += length;
573  }
574}
575
576void
577IpcpInput(struct mbuf *bp)
578{
579  FsmInput(&IpcpFsm, bp);
580}
581