ipcp.c revision 15738
16059Samurai/*
26059Samurai *	PPP IP Control Protocol (IPCP) Module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196059Samurai *
2015738Sphk * $Id: ipcp.c,v 1.7 1996/01/11 17:48:50 phk Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o More RFC1772 backwoard compatibility
246059Samurai */
256059Samurai#include "fsm.h"
266059Samurai#include "lcpproto.h"
276059Samurai#include "lcp.h"
286059Samurai#include "ipcp.h"
296059Samurai#include <netdb.h>
306059Samurai#include <netinet/in_systm.h>
316059Samurai#include <netinet/ip.h>
326059Samurai#include <arpa/inet.h>
336059Samurai#include <sys/socket.h>
346059Samurai#include "slcompress.h"
356059Samurai#include "os.h"
366059Samurai#include "phase.h"
376059Samurai#include "vars.h"
386059Samurai
396059Samuraiextern void PutConfValue();
406059Samuraiextern void Prompt();
416059Samuraiextern struct in_addr ifnetmask;
426059Samurai
436059Samuraistruct ipcpstate IpcpInfo;
449440Samuraistruct in_range DefMyAddress, DefHisAddress, DefTriggerAddress;
456059Samurai
466735Samuraistatic void IpcpSendConfigReq __P((struct fsm *));
476735Samuraistatic void IpcpSendTerminateAck __P((struct fsm *));
486735Samuraistatic void IpcpSendTerminateReq __P((struct fsm *));
496735Samuraistatic void IpcpDecodeConfig __P((u_char *, int, int));
506735Samuraistatic void IpcpLayerStart __P((struct fsm *));
516735Samuraistatic void IpcpLayerFinish __P((struct fsm *));
526735Samuraistatic void IpcpLayerUp __P((struct fsm *));
536735Samuraistatic void IpcpLayerDown __P((struct fsm *));
546735Samuraistatic void IpcpInitRestartCounter __P((struct fsm *));
556059Samurai
567001Samuraistruct pppTimer IpcpReportTimer;
576059Samurai
586059Samuraistatic int lastInOctets, lastOutOctets;
596059Samurai
606059Samurai#define	REJECTED(p, x)	(p->his_reject & (1<<x))
616059Samurai
626059Samuraistruct fsm IpcpFsm = {
636059Samurai  "IPCP",
646059Samurai  PROTO_IPCP,
656059Samurai  IPCP_MAXCODE,
666059Samurai  OPEN_ACTIVE,
676059Samurai  ST_INITIAL,
686059Samurai  0, 0, 0,
696059Samurai
706059Samurai  0,
716059Samurai  { 0, 0, 0, NULL, NULL, NULL },
726059Samurai
736059Samurai  IpcpLayerUp,
746059Samurai  IpcpLayerDown,
756059Samurai  IpcpLayerStart,
766059Samurai  IpcpLayerFinish,
776059Samurai  IpcpInitRestartCounter,
786059Samurai  IpcpSendConfigReq,
796059Samurai  IpcpSendTerminateReq,
806059Samurai  IpcpSendTerminateAck,
816059Samurai  IpcpDecodeConfig,
826059Samurai};
836059Samurai
846059Samuraistatic char *cftypes[] = {
856059Samurai  "???", "IPADDRS", "COMPPROTO", "IPADDR",
866059Samurai};
876059Samurai
886059Samurai/*
896059Samurai * Function called every second. Updates connection period and idle period,
906059Samurai * also update LQR information.
916059Samurai */
926059Samuraistatic void
936059SamuraiIpcpReportFunc()
946059Samurai{
956059Samurai  ipConnectSecs++;
966059Samurai  if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets)
976059Samurai    ipIdleSecs++;
986059Samurai  lastInOctets = ipInOctets;
996059Samurai  lastOutOctets = ipOutOctets;
1006059Samurai  StopTimer(&IpcpReportTimer);
1016059Samurai  IpcpReportTimer.state = TIMER_STOPPED;
1026059Samurai  StartTimer(&IpcpReportTimer);
1036059Samurai}
1046059Samurai
1056059Samuraistatic void
1066059SamuraiIpcpStartReport()
1076059Samurai{
1086059Samurai  ipIdleSecs = ipConnectSecs = 0;
1096059Samurai  StopTimer(&IpcpReportTimer);
1106059Samurai  IpcpReportTimer.state = TIMER_STOPPED;
1116059Samurai  IpcpReportTimer.load = SECTICKS;
1126059Samurai  IpcpReportTimer.func = IpcpReportFunc;
1136059Samurai  StartTimer(&IpcpReportTimer);
1146059Samurai}
1156059Samurai
1166059Samuraivoid
1176059SamuraiReportIpcpStatus()
1186059Samurai{
1196059Samurai  struct ipcpstate *icp = &IpcpInfo;
1206059Samurai  struct fsm *fp = &IpcpFsm;
1216059Samurai
1226059Samurai  printf("%s [%s]\n", fp->name, StateNames[fp->state]);
12313389Sphk  printf(" his side: %s, %lx\n",
1246059Samurai     inet_ntoa(icp->his_ipaddr), icp->his_compproto);
12513389Sphk  printf(" my  side: %s, %lx\n",
1266059Samurai     inet_ntoa(icp->want_ipaddr), icp->want_compproto);
1276059Samurai  printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs);
1289440Samurai  printf("Defaults:\n");
1299440Samurai  printf(" My Address:  %s/%d\n",
1306059Samurai     inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width);
1319440Samurai  printf(" His Address: %s/%d\n",
1326059Samurai     inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width);
1339440Samurai  printf(" Negotiation: %s/%d\n",
1349440Samurai     inet_ntoa(DefTriggerAddress.ipaddr), DefTriggerAddress.width);
1356059Samurai}
1366059Samurai
1376059Samuraivoid
1386059SamuraiIpcpDefAddress()
1396059Samurai{
1406059Samurai  struct hostent *hp;
1416059Samurai  char name[200];
1426059Samurai
1436059Samurai  bzero(&DefMyAddress, sizeof(DefMyAddress));
1446059Samurai  bzero(&DefHisAddress, sizeof(DefHisAddress));
1459440Samurai  bzero(&DefTriggerAddress, sizeof(DefTriggerAddress));
1466059Samurai  if (gethostname(name, sizeof(name)) == 0) {
1476059Samurai      hp = gethostbyname(name);
1486059Samurai      if (hp && hp->h_addrtype == AF_INET) {
1496059Samurai	bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length);
1506059Samurai      }
1516059Samurai  }
1526059Samurai}
1536059Samurai
1546059Samuraivoid
1556059SamuraiIpcpInit()
1566059Samurai{
1576059Samurai  struct ipcpstate *icp = &IpcpInfo;
1586059Samurai
1596059Samurai  FsmInit(&IpcpFsm);
1606059Samurai  bzero(icp, sizeof(struct ipcpstate));
1616059Samurai  if ((mode & MODE_DEDICATED) && !dstsystem) {
1626059Samurai    icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0;
1636059Samurai  } else {
1646059Samurai    icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
1656059Samurai    icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
1666059Samurai  }
1679440Samurai
1689440Samurai  /*
1699440Samurai   * Some implementation of PPP are:
1709440Samurai   *  Starting a negotiaion by require sending *special* value as my address,
1719440Samurai   *  even though standard of PPP is defined full negotiation based.
1729440Samurai   *  (e.g. "0.0.0.0" or Not "0.0.0.0")
1739440Samurai   */
1749440Samurai  if ( icp->want_ipaddr.s_addr == 0 ) {
1759440Samurai    icp->want_ipaddr.s_addr = DefTriggerAddress.ipaddr.s_addr;
1769440Samurai  }
1779440Samurai
1786059Samurai  if (Enabled(ConfVjcomp))
1796059Samurai    icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8);
1806059Samurai  else
1816059Samurai    icp->want_compproto = 0;
1826059Samurai  icp->heis1172 = 0;
1836059Samurai  IpcpFsm.maxconfig = 10;
1846059Samurai}
1856059Samurai
1866059Samuraistatic void
1876059SamuraiIpcpInitRestartCounter(fp)
1886059Samuraistruct fsm *fp;
1896059Samurai{
1906735Samurai  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
1916059Samurai  fp->restart = 5;
1926059Samurai}
1936059Samurai
1946059Samuraistatic void
1956059SamuraiIpcpSendConfigReq(fp)
1966059Samuraistruct fsm *fp;
1976059Samurai{
1986059Samurai  u_char *cp;
1996059Samurai  struct ipcpstate *icp = &IpcpInfo;
2006059Samurai
2016059Samurai  cp = ReqBuff;
20215738Sphk  LogPrintf(LOG_LCP_BIT, "%s: SendConfigReq\n", fp->name);
2036735Samurai  if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR))
2046735Samurai    PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr));
2056059Samurai  if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) {
2066059Samurai    if (icp->heis1172)
2076059Samurai      PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16);
2086059Samurai    else
2096059Samurai      PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto);
2106059Samurai  }
2116059Samurai  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
2126059Samurai}
2136059Samurai
2146059Samuraistatic void
2156059SamuraiIpcpSendTerminateReq(fp)
2166059Samuraistruct fsm *fp;
2176059Samurai{
2186059Samurai  /* XXX: No code yet */
2196059Samurai}
2206059Samurai
2216059Samuraistatic void
2226059SamuraiIpcpSendTerminateAck(fp)
2236059Samuraistruct fsm *fp;
2246059Samurai{
22515738Sphk  LogPrintf(LOG_LCP_BIT, "  %s: SendTerminateAck\n", fp->name);
2266059Samurai  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
2276059Samurai}
2286059Samurai
2296059Samuraistatic void
2306059SamuraiIpcpLayerStart(fp)
2316059Samuraistruct fsm *fp;
2326059Samurai{
23315738Sphk  LogPrintf(LOG_LCP_BIT, "%s: LayerStart.\n", fp->name);
2346059Samurai}
2356059Samurai
2366059Samuraistatic void
2376059SamuraiIpcpLayerFinish(fp)
2386059Samuraistruct fsm *fp;
2396059Samurai{
24015738Sphk  LogPrintf(LOG_LCP_BIT, "%s: LayerFinish.\n", fp->name);
2416059Samurai  LcpClose();
2426059Samurai  NewPhase(PHASE_TERMINATE);
2436059Samurai}
2446059Samurai
2456059Samuraistatic void
2466059SamuraiIpcpLayerDown(fp)
2476059Samuraistruct fsm *fp;
2486059Samurai{
24915738Sphk  LogPrintf(LOG_LCP_BIT, "%s: LayerDown.\n", fp->name);
2506059Samurai  StopTimer(&IpcpReportTimer);
2516059Samurai}
2526059Samurai
2536059Samurai/*
2546059Samurai *  Called when IPCP has reached to OPEN state
2556059Samurai */
2566059Samuraistatic void
2576059SamuraiIpcpLayerUp(fp)
2586059Samuraistruct fsm *fp;
2596059Samurai{
2606059Samurai  char tbuff[100];
2616059Samurai
2626059Samurai#ifdef VERBOSE
2636059Samurai  fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state);
2646059Samurai#endif
2656059Samurai  Prompt(1);
26615738Sphk  LogPrintf(LOG_LCP_BIT, "%s: LayerUp.\n", fp->name);
2676059Samurai  sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr));
26815738Sphk  LogPrintf(LOG_LCP_BIT|LOG_LINK_BIT, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
2696059Samurai  OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
2706059Samurai  OsLinkup();
2716059Samurai  IpcpStartReport();
2726059Samurai  StartIdleTimer();
2736059Samurai}
2746059Samurai
2756059Samuraivoid
2766059SamuraiIpcpUp()
2776059Samurai{
2786059Samurai  FsmUp(&IpcpFsm);
27915738Sphk  LogPrintf(LOG_LCP_BIT, "IPCP Up event!!\n");
2806059Samurai}
2816059Samurai
2826059Samuraivoid
2836059SamuraiIpcpOpen()
2846059Samurai{
2856059Samurai  FsmOpen(&IpcpFsm);
2866059Samurai}
2876059Samurai
2886059Samuraistatic int
2896059SamuraiAcceptableAddr(prange, ipaddr)
2906059Samuraistruct in_range *prange;
2916059Samuraistruct in_addr ipaddr;
2926059Samurai{
2936059Samurai#ifdef DEBUG
2946059Samurai  logprintf("requested = %x ", htonl(ipaddr.s_addr));
2956059Samurai  logprintf("range = %x", htonl(prange->ipaddr.s_addr));
2966059Samurai  logprintf("/%x\n", htonl(prange->mask.s_addr));
2976059Samurai  logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr),
2986059Samurai    htonl(ipaddr.s_addr & prange->mask.s_addr));
2996059Samurai#endif
3006059Samurai  return((prange->ipaddr.s_addr & prange->mask.s_addr) ==
3016059Samurai	(ipaddr.s_addr & prange->mask.s_addr));
3026059Samurai}
3036059Samurai
3046059Samuraistatic void
3056735SamuraiIpcpDecodeConfig(cp, plen, mode)
3066735Samuraiu_char *cp;
3076735Samuraiint plen;
3086059Samuraiint mode;
3096059Samurai{
3106735Samurai  int type, length;
3116059Samurai  u_long *lp, compproto;
3126059Samurai  struct compreq *pcomp;
3136059Samurai  struct in_addr ipaddr, dstipaddr;
3146059Samurai  char tbuff[100];
3156059Samurai
3166059Samurai  ackp = AckBuff;
3176059Samurai  nakp = NakBuff;
3186059Samurai  rejp = RejBuff;
3196059Samurai
3206059Samurai  while (plen >= sizeof(struct fsmconfig)) {
3216059Samurai    if (plen < 0)
3226059Samurai      break;
3236059Samurai    type = *cp;
3246059Samurai    length = cp[1];
3256059Samurai    if (type <= TY_IPADDR)
3266059Samurai      sprintf(tbuff, " %s[%d] ", cftypes[type], length);
3276059Samurai    else
3286059Samurai      sprintf(tbuff, " ");
3296059Samurai
3306059Samurai    switch (type) {
3316059Samurai    case TY_IPADDR:		/* RFC1332 */
3326059Samurai      lp = (u_long *)(cp + 2);
3336059Samurai      ipaddr.s_addr = *lp;
33415738Sphk      LogPrintf(LOG_LCP_BIT, "%s %s\n", tbuff, inet_ntoa(ipaddr));
3356059Samurai
3366059Samurai      switch (mode) {
3376059Samurai      case MODE_REQ:
3386059Samurai	if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
3396059Samurai          /*
3406059Samurai           * If destination address is not acceptable, insist to use
3416059Samurai           * what we want to use.
3426059Samurai           */
3436059Samurai	  bcopy(cp, nakp, 2);
3446059Samurai          bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length);
3456059Samurai          nakp += length;
3466059Samurai          break;
3478857Srgrimes
3486059Samurai	}
3496059Samurai	IpcpInfo.his_ipaddr = ipaddr;
3506059Samurai	bcopy(cp, ackp, length);
3516059Samurai	ackp += length;
3526059Samurai	break;
3536059Samurai      case MODE_NAK:
3546059Samurai	if (AcceptableAddr(&DefMyAddress, ipaddr)) {
3556059Samurai          /*
3566059Samurai           * Use address suggested by peer.
3576059Samurai           */
3586059Samurai	  sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
35915738Sphk	  LogPrintf(LOG_LCP_BIT, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr));
3606059Samurai	  IpcpInfo.want_ipaddr = ipaddr;
3616059Samurai	}
3626059Samurai	break;
3636059Samurai      case MODE_REJ:
3646059Samurai	IpcpInfo.his_reject |= (1 << type);
3656059Samurai	break;
3666059Samurai      }
3676059Samurai      break;
3686059Samurai    case TY_COMPPROTO:
3696059Samurai      lp = (u_long *)(cp + 2);
3706059Samurai      compproto = htonl(*lp);
37115738Sphk      LogPrintf(LOG_LCP_BIT, "%s %08x\n", tbuff, compproto);
3726059Samurai
3736059Samurai      switch (mode) {
3746059Samurai      case MODE_REQ:
3756059Samurai	if (!Acceptable(ConfVjcomp)) {
3766059Samurai	  bcopy(cp, rejp, length);
3776059Samurai	  rejp += length;
3786059Samurai	} else {
3796059Samurai	  pcomp = (struct compreq *)(cp + 2);
3806059Samurai	  switch (length) {
3816059Samurai	  case 4:	/* RFC1172 */
3826059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
3836059Samurai	      logprintf("** Peer is speaking RFC1172 compression protocol **\n");
3846059Samurai	      IpcpInfo.heis1172 = 1;
3856059Samurai	      IpcpInfo.his_compproto = compproto;
3866059Samurai	      bcopy(cp, ackp, length);
3876059Samurai	      ackp += length;
3886059Samurai	    } else {
3896059Samurai	      bcopy(cp, nakp, 2);
3906059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
3916059Samurai	      bcopy(&pcomp, nakp + 2, 2);
3926059Samurai	      nakp += length;
3936059Samurai	    }
3946059Samurai	    break;
3956059Samurai	  case 6: 	/* RFC1332 */
3966059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
3976059Samurai	        && pcomp->slots < MAX_STATES && pcomp->slots > 2) {
3986059Samurai	      IpcpInfo.his_compproto = compproto;
3996059Samurai	      IpcpInfo.heis1172 = 0;
4006059Samurai	      bcopy(cp, ackp, length);
4016059Samurai	      ackp += length;
4026059Samurai	    } else {
4036059Samurai	      bcopy(cp, nakp, 2);
4046059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
4056059Samurai	      pcomp->slots = MAX_STATES - 1;
4066059Samurai	      pcomp->compcid = 0;
4076059Samurai	      bcopy(&pcomp, nakp + 2, sizeof(pcomp));
4086059Samurai	      nakp += length;
4096059Samurai	    }
4106059Samurai	    break;
4116059Samurai	  default:
4126059Samurai	    bcopy(cp, rejp, length);
4136059Samurai	    rejp += length;
4146059Samurai	    break;
4156059Samurai	  }
4166059Samurai	}
4176059Samurai	break;
4186059Samurai      case MODE_NAK:
41915738Sphk	LogPrintf(LOG_LCP_BIT, "%s changing compproto: %08x --> %08x\n",
4206059Samurai	  tbuff, IpcpInfo.want_compproto, compproto);
4216059Samurai	IpcpInfo.want_compproto = compproto;
4226059Samurai	break;
4236059Samurai      case MODE_REJ:
4246059Samurai	IpcpInfo.his_reject |= (1 << type);
4256059Samurai	break;
4266059Samurai      }
4276059Samurai      break;
4286059Samurai    case TY_IPADDRS:	/* RFC1172 */
4296059Samurai      lp = (u_long *)(cp + 2);
4306059Samurai      ipaddr.s_addr = *lp;
4316059Samurai      lp = (u_long *)(cp + 6);
4326059Samurai      dstipaddr.s_addr = *lp;
43315738Sphk      LogPrintf(LOG_LCP_BIT, "%s %s, ", tbuff, inet_ntoa(ipaddr));
43415738Sphk      LogPrintf(LOG_LCP_BIT, "%s\n", inet_ntoa(dstipaddr));
4356059Samurai
4366059Samurai      switch (mode) {
4376059Samurai      case MODE_REQ:
4386059Samurai	IpcpInfo.his_ipaddr = ipaddr;
4396059Samurai	IpcpInfo.want_ipaddr = dstipaddr;
4406059Samurai	bcopy(cp, ackp, length);
4416059Samurai	ackp += length;
4426059Samurai	break;
4436059Samurai      case MODE_NAK:
44415738Sphk	LogPrintf(LOG_LCP_BIT, "%s changing address: %s ",
4456059Samurai	  tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
44615738Sphk	LogPrintf(LOG_LCP_BIT, "--> %s\n", inet_ntoa(ipaddr));
4476059Samurai	IpcpInfo.want_ipaddr = ipaddr;
4486059Samurai	IpcpInfo.his_ipaddr = dstipaddr;
4496059Samurai	break;
4506059Samurai      case MODE_REJ:
4516059Samurai	IpcpInfo.his_reject |= (1 << type);
4526059Samurai	break;
4536059Samurai      }
4546059Samurai      break;
4556059Samurai    default:
4566059Samurai      IpcpInfo.my_reject |= (1 << type);
4576059Samurai      bcopy(cp, rejp, length);
4586059Samurai      rejp += length;
4596059Samurai      break;
4606059Samurai    }
4616059Samurai    plen -= length;
4626059Samurai    cp += length;
4636059Samurai  }
4646059Samurai}
4656059Samurai
4666059Samuraivoid
4676059SamuraiIpcpInput(struct mbuf *bp)
4686059Samurai{
4696059Samurai  FsmInput(&IpcpFsm, bp);
4706059Samurai}
471