ipcp.c revision 8857
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 *
208857Srgrimes * $Id: ipcp.c,v 1.3 1995/03/11 15:18:44 amurai 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;
446059Samuraistruct in_range DefMyAddress, DefHisAddress;
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]);
1236059Samurai  printf(" his side: %s, %x\n",
1246059Samurai     inet_ntoa(icp->his_ipaddr), icp->his_compproto);
1256059Samurai  printf(" my  side: %s, %x\n",
1266059Samurai     inet_ntoa(icp->want_ipaddr), icp->want_compproto);
1276059Samurai  printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs);
1286059Samurai  printf("Defaults:  My Address: %s/%d  ",
1296059Samurai     inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width);
1306059Samurai  printf("His Address: %s/%d\n",
1316059Samurai     inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width);
1326059Samurai}
1336059Samurai
1346059Samuraivoid
1356059SamuraiIpcpDefAddress()
1366059Samurai{
1376059Samurai  struct hostent *hp;
1386059Samurai  char name[200];
1396059Samurai
1406059Samurai  bzero(&DefMyAddress, sizeof(DefMyAddress));
1416059Samurai  bzero(&DefHisAddress, sizeof(DefHisAddress));
1426059Samurai  if (gethostname(name, sizeof(name)) == 0) {
1436059Samurai      hp = gethostbyname(name);
1446059Samurai      if (hp && hp->h_addrtype == AF_INET) {
1456059Samurai	bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length);
1466059Samurai      }
1476059Samurai  }
1486059Samurai}
1496059Samurai
1506059Samuraivoid
1516059SamuraiIpcpInit()
1526059Samurai{
1536059Samurai  struct ipcpstate *icp = &IpcpInfo;
1546059Samurai
1556059Samurai  FsmInit(&IpcpFsm);
1566059Samurai  bzero(icp, sizeof(struct ipcpstate));
1576059Samurai  if ((mode & MODE_DEDICATED) && !dstsystem) {
1586059Samurai    icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0;
1596059Samurai  } else {
1606059Samurai    icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
1616059Samurai    icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
1626059Samurai  }
1636059Samurai  if (icp->want_ipaddr.s_addr == 0)
1646059Samurai    icp->want_ipaddr.s_addr = htonl(0xc0000001);
1656059Samurai  if (Enabled(ConfVjcomp))
1666059Samurai    icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8);
1676059Samurai  else
1686059Samurai    icp->want_compproto = 0;
1696059Samurai  icp->heis1172 = 0;
1706059Samurai  IpcpFsm.maxconfig = 10;
1716059Samurai}
1726059Samurai
1736059Samuraistatic void
1746059SamuraiIpcpInitRestartCounter(fp)
1756059Samuraistruct fsm *fp;
1766059Samurai{
1776735Samurai  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
1786059Samurai  fp->restart = 5;
1796059Samurai}
1806059Samurai
1816059Samuraistatic void
1826059SamuraiIpcpSendConfigReq(fp)
1836059Samuraistruct fsm *fp;
1846059Samurai{
1856059Samurai  u_char *cp;
1866059Samurai  struct ipcpstate *icp = &IpcpInfo;
1876059Samurai
1886059Samurai  cp = ReqBuff;
1896059Samurai  LogPrintf(LOG_LCP, "%s: SendConfigReq\n", fp->name);
1906735Samurai  if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR))
1916735Samurai    PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr));
1926059Samurai  if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) {
1936059Samurai    if (icp->heis1172)
1946059Samurai      PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16);
1956059Samurai    else
1966059Samurai      PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto);
1976059Samurai  }
1986059Samurai  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
1996059Samurai}
2006059Samurai
2016059Samuraistatic void
2026059SamuraiIpcpSendTerminateReq(fp)
2036059Samuraistruct fsm *fp;
2046059Samurai{
2056059Samurai  /* XXX: No code yet */
2066059Samurai}
2076059Samurai
2086059Samuraistatic void
2096059SamuraiIpcpSendTerminateAck(fp)
2106059Samuraistruct fsm *fp;
2116059Samurai{
2126059Samurai  LogPrintf(LOG_LCP, "  %s: SendTerminateAck\n", fp->name);
2136059Samurai  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
2146059Samurai}
2156059Samurai
2166059Samuraistatic void
2176059SamuraiIpcpLayerStart(fp)
2186059Samuraistruct fsm *fp;
2196059Samurai{
2206059Samurai  LogPrintf(LOG_LCP, "%s: LayerStart.\n", fp->name);
2216059Samurai}
2226059Samurai
2236059Samuraistatic void
2246059SamuraiIpcpLayerFinish(fp)
2256059Samuraistruct fsm *fp;
2266059Samurai{
2276059Samurai  LogPrintf(LOG_LCP, "%s: LayerFinish.\n", fp->name);
2286059Samurai  LcpClose();
2296059Samurai  NewPhase(PHASE_TERMINATE);
2306059Samurai}
2316059Samurai
2326059Samuraistatic void
2336059SamuraiIpcpLayerDown(fp)
2346059Samuraistruct fsm *fp;
2356059Samurai{
2366059Samurai  LogPrintf(LOG_LCP, "%s: LayerDown.\n", fp->name);
2376059Samurai  StopTimer(&IpcpReportTimer);
2386059Samurai}
2396059Samurai
2406059Samurai/*
2416059Samurai *  Called when IPCP has reached to OPEN state
2426059Samurai */
2436059Samuraistatic void
2446059SamuraiIpcpLayerUp(fp)
2456059Samuraistruct fsm *fp;
2466059Samurai{
2476059Samurai  char tbuff[100];
2486059Samurai
2496059Samurai#ifdef VERBOSE
2506059Samurai  fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state);
2516059Samurai#endif
2526059Samurai  Prompt(1);
2536059Samurai  LogPrintf(LOG_LCP, "%s: LayerUp.\n", fp->name);
2546059Samurai  sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr));
2556059Samurai  LogPrintf(LOG_LCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
2566059Samurai  OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
2576059Samurai  OsLinkup();
2586059Samurai  IpcpStartReport();
2596059Samurai  StartIdleTimer();
2606059Samurai}
2616059Samurai
2626059Samuraivoid
2636059SamuraiIpcpUp()
2646059Samurai{
2656059Samurai  FsmUp(&IpcpFsm);
2666059Samurai  LogPrintf(LOG_LCP, "IPCP Up event!!\n");
2676059Samurai}
2686059Samurai
2696059Samuraivoid
2706059SamuraiIpcpOpen()
2716059Samurai{
2726059Samurai  FsmOpen(&IpcpFsm);
2736059Samurai}
2746059Samurai
2756059Samuraistatic int
2766059SamuraiAcceptableAddr(prange, ipaddr)
2776059Samuraistruct in_range *prange;
2786059Samuraistruct in_addr ipaddr;
2796059Samurai{
2806059Samurai#ifdef DEBUG
2816059Samurai  logprintf("requested = %x ", htonl(ipaddr.s_addr));
2826059Samurai  logprintf("range = %x", htonl(prange->ipaddr.s_addr));
2836059Samurai  logprintf("/%x\n", htonl(prange->mask.s_addr));
2846059Samurai  logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr),
2856059Samurai    htonl(ipaddr.s_addr & prange->mask.s_addr));
2866059Samurai#endif
2876059Samurai  return((prange->ipaddr.s_addr & prange->mask.s_addr) ==
2886059Samurai	(ipaddr.s_addr & prange->mask.s_addr));
2896059Samurai}
2906059Samurai
2916059Samuraistatic void
2926735SamuraiIpcpDecodeConfig(cp, plen, mode)
2936735Samuraiu_char *cp;
2946735Samuraiint plen;
2956059Samuraiint mode;
2966059Samurai{
2976735Samurai  int type, length;
2986059Samurai  u_long *lp, compproto;
2996059Samurai  struct compreq *pcomp;
3006059Samurai  struct in_addr ipaddr, dstipaddr;
3016059Samurai  char tbuff[100];
3026059Samurai
3036059Samurai  ackp = AckBuff;
3046059Samurai  nakp = NakBuff;
3056059Samurai  rejp = RejBuff;
3066059Samurai
3076059Samurai  while (plen >= sizeof(struct fsmconfig)) {
3086059Samurai    if (plen < 0)
3096059Samurai      break;
3106059Samurai    type = *cp;
3116059Samurai    length = cp[1];
3126059Samurai    if (type <= TY_IPADDR)
3136059Samurai      sprintf(tbuff, " %s[%d] ", cftypes[type], length);
3146059Samurai    else
3156059Samurai      sprintf(tbuff, " ");
3166059Samurai
3176059Samurai    switch (type) {
3186059Samurai    case TY_IPADDR:		/* RFC1332 */
3196059Samurai      lp = (u_long *)(cp + 2);
3206059Samurai      ipaddr.s_addr = *lp;
3216059Samurai      LogPrintf(LOG_LCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
3226059Samurai
3236059Samurai      switch (mode) {
3246059Samurai      case MODE_REQ:
3256059Samurai	if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
3266059Samurai          /*
3276059Samurai           * If destination address is not acceptable, insist to use
3286059Samurai           * what we want to use.
3296059Samurai           */
3306059Samurai	  bcopy(cp, nakp, 2);
3316059Samurai          bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length);
3326059Samurai          nakp += length;
3336059Samurai          break;
3348857Srgrimes
3356059Samurai	}
3366059Samurai	IpcpInfo.his_ipaddr = ipaddr;
3376059Samurai	bcopy(cp, ackp, length);
3386059Samurai	ackp += length;
3396059Samurai	break;
3406059Samurai      case MODE_NAK:
3416059Samurai	if (AcceptableAddr(&DefMyAddress, ipaddr)) {
3426059Samurai          /*
3436059Samurai           * Use address suggested by peer.
3446059Samurai           */
3456059Samurai	  sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
3466059Samurai	  LogPrintf(LOG_LCP, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr));
3476059Samurai	  IpcpInfo.want_ipaddr = ipaddr;
3486059Samurai	}
3496059Samurai	break;
3506059Samurai      case MODE_REJ:
3516059Samurai	IpcpInfo.his_reject |= (1 << type);
3526059Samurai	break;
3536059Samurai      }
3546059Samurai      break;
3556059Samurai    case TY_COMPPROTO:
3566059Samurai      lp = (u_long *)(cp + 2);
3576059Samurai      compproto = htonl(*lp);
3586059Samurai      LogPrintf(LOG_LCP, "%s %08x\n", tbuff, compproto);
3596059Samurai
3606059Samurai      switch (mode) {
3616059Samurai      case MODE_REQ:
3626059Samurai	if (!Acceptable(ConfVjcomp)) {
3636059Samurai	  bcopy(cp, rejp, length);
3646059Samurai	  rejp += length;
3656059Samurai	} else {
3666059Samurai	  pcomp = (struct compreq *)(cp + 2);
3676059Samurai	  switch (length) {
3686059Samurai	  case 4:	/* RFC1172 */
3696059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
3706059Samurai	      logprintf("** Peer is speaking RFC1172 compression protocol **\n");
3716059Samurai	      IpcpInfo.heis1172 = 1;
3726059Samurai	      IpcpInfo.his_compproto = compproto;
3736059Samurai	      bcopy(cp, ackp, length);
3746059Samurai	      ackp += length;
3756059Samurai	    } else {
3766059Samurai	      bcopy(cp, nakp, 2);
3776059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
3786059Samurai	      bcopy(&pcomp, nakp + 2, 2);
3796059Samurai	      nakp += length;
3806059Samurai	    }
3816059Samurai	    break;
3826059Samurai	  case 6: 	/* RFC1332 */
3836059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
3846059Samurai	        && pcomp->slots < MAX_STATES && pcomp->slots > 2) {
3856059Samurai	      IpcpInfo.his_compproto = compproto;
3866059Samurai	      IpcpInfo.heis1172 = 0;
3876059Samurai	      bcopy(cp, ackp, length);
3886059Samurai	      ackp += length;
3896059Samurai	    } else {
3906059Samurai	      bcopy(cp, nakp, 2);
3916059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
3926059Samurai	      pcomp->slots = MAX_STATES - 1;
3936059Samurai	      pcomp->compcid = 0;
3946059Samurai	      bcopy(&pcomp, nakp + 2, sizeof(pcomp));
3956059Samurai	      nakp += length;
3966059Samurai	    }
3976059Samurai	    break;
3986059Samurai	  default:
3996059Samurai	    bcopy(cp, rejp, length);
4006059Samurai	    rejp += length;
4016059Samurai	    break;
4026059Samurai	  }
4036059Samurai	}
4046059Samurai	break;
4056059Samurai      case MODE_NAK:
4066059Samurai	LogPrintf(LOG_LCP, "%s changing compproto: %08x --> %08x\n",
4076059Samurai	  tbuff, IpcpInfo.want_compproto, compproto);
4086059Samurai	IpcpInfo.want_compproto = compproto;
4096059Samurai	break;
4106059Samurai      case MODE_REJ:
4116059Samurai	IpcpInfo.his_reject |= (1 << type);
4126059Samurai	break;
4136059Samurai      }
4146059Samurai      break;
4156059Samurai    case TY_IPADDRS:	/* RFC1172 */
4166059Samurai      lp = (u_long *)(cp + 2);
4176059Samurai      ipaddr.s_addr = *lp;
4186059Samurai      lp = (u_long *)(cp + 6);
4196059Samurai      dstipaddr.s_addr = *lp;
4206059Samurai      LogPrintf(LOG_LCP, "%s %s, ", tbuff, inet_ntoa(ipaddr));
4216059Samurai      LogPrintf(LOG_LCP, "%s\n", inet_ntoa(dstipaddr));
4226059Samurai
4236059Samurai      switch (mode) {
4246059Samurai      case MODE_REQ:
4256059Samurai	IpcpInfo.his_ipaddr = ipaddr;
4266059Samurai	IpcpInfo.want_ipaddr = dstipaddr;
4276059Samurai	bcopy(cp, ackp, length);
4286059Samurai	ackp += length;
4296059Samurai	break;
4306059Samurai      case MODE_NAK:
4316059Samurai	LogPrintf(LOG_LCP, "%s changing address: %s ",
4326059Samurai	  tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
4336059Samurai	LogPrintf(LOG_LCP, "--> %s\n", inet_ntoa(ipaddr));
4346059Samurai	IpcpInfo.want_ipaddr = ipaddr;
4356059Samurai	IpcpInfo.his_ipaddr = dstipaddr;
4366059Samurai	break;
4376059Samurai      case MODE_REJ:
4386059Samurai	IpcpInfo.his_reject |= (1 << type);
4396059Samurai	break;
4406059Samurai      }
4416059Samurai      break;
4426059Samurai    default:
4436059Samurai      IpcpInfo.my_reject |= (1 << type);
4446059Samurai      bcopy(cp, rejp, length);
4456059Samurai      rejp += length;
4466059Samurai      break;
4476059Samurai    }
4486059Samurai    plen -= length;
4496059Samurai    cp += length;
4506059Samurai  }
4516059Samurai}
4526059Samurai
4536059Samuraivoid
4546059SamuraiIpcpInput(struct mbuf *bp)
4556059Samurai{
4566059Samurai  FsmInput(&IpcpFsm, bp);
4576059Samurai}
458