ipcp.c revision 31034
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 *
2031034Sbrian * $Id: ipcp.c,v 1.33 1997/10/29 01:19:40 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o More RFC1772 backwoard compatibility
246059Samurai */
2530715Sbrian#include <sys/param.h>
266059Samurai#include <netinet/in_systm.h>
2729048Sbrian#include <netinet/in.h>
286059Samurai#include <netinet/ip.h>
296059Samurai#include <arpa/inet.h>
306059Samurai#include <sys/socket.h>
3130715Sbrian#include <netdb.h>
3230715Sbrian
3329048Sbrian#include <limits.h>
3430715Sbrian#include <stdio.h>
3530715Sbrian#include <string.h>
3630715Sbrian#include <unistd.h>
3730715Sbrian
3830715Sbrian#include "mbuf.h"
3930715Sbrian#include "log.h"
4030715Sbrian#include "defs.h"
4130715Sbrian#include "timer.h"
4229048Sbrian#include "fsm.h"
4329048Sbrian#include "lcpproto.h"
4429048Sbrian#include "lcp.h"
4529048Sbrian#include "ipcp.h"
466059Samurai#include "slcompress.h"
476059Samurai#include "os.h"
486059Samurai#include "phase.h"
4926142Sbrian#include "loadalias.h"
5030715Sbrian#include "command.h"
516059Samurai#include "vars.h"
5230715Sbrian#include "vjcomp.h"
5330733Sbrian#include "ip.h"
546059Samurai
5530715Sbrian#ifndef NOMSEXT
5630715Sbrianstruct in_addr ns_entries[2];
5730715Sbrianstruct in_addr nbns_entries[2];
5830715Sbrian#endif
596059Samurai
606059Samuraistruct ipcpstate IpcpInfo;
6130715Sbrianstruct in_range  DefMyAddress;
6230715Sbrianstruct in_range  DefHisAddress;
6330715Sbrianstruct in_addr   TriggerAddress;
6428394Sbrianint HaveTriggerAddress;
6530715Sbrianstruct pppTimer IpcpReportTimer;
666059Samurai
6726516Sbrianstatic void IpcpSendConfigReq(struct fsm *);
6826516Sbrianstatic void IpcpSendTerminateAck(struct fsm *);
6926516Sbrianstatic void IpcpSendTerminateReq(struct fsm *);
7026516Sbrianstatic void IpcpDecodeConfig(u_char *, int, int);
7126516Sbrianstatic void IpcpLayerStart(struct fsm *);
7226516Sbrianstatic void IpcpLayerFinish(struct fsm *);
7326516Sbrianstatic void IpcpLayerUp(struct fsm *);
7426516Sbrianstatic void IpcpLayerDown(struct fsm *);
7526516Sbrianstatic void IpcpInitRestartCounter(struct fsm *);
7630715Sbrianstatic int  IpcpOctetsIn(void);
7730715Sbrianstatic int  IpcpOctetsOut(void);
786059Samurai
796059Samuraistatic int lastInOctets, lastOutOctets;
8029048Sbrianstatic int StartingIpIn, StartingIpOut;
816059Samurai
826059Samurai#define	REJECTED(p, x)	(p->his_reject & (1<<x))
836059Samurai
846059Samuraistruct fsm IpcpFsm = {
856059Samurai  "IPCP",
866059Samurai  PROTO_IPCP,
876059Samurai  IPCP_MAXCODE,
886059Samurai  OPEN_ACTIVE,
896059Samurai  ST_INITIAL,
906059Samurai  0, 0, 0,
916059Samurai
926059Samurai  0,
9328679Sbrian  {0, 0, 0, NULL, NULL, NULL},
9428679Sbrian  {0, 0, 0, NULL, NULL, NULL},
9528461Sbrian  LogIPCP,
966059Samurai
976059Samurai  IpcpLayerUp,
986059Samurai  IpcpLayerDown,
996059Samurai  IpcpLayerStart,
1006059Samurai  IpcpLayerFinish,
1016059Samurai  IpcpInitRestartCounter,
1026059Samurai  IpcpSendConfigReq,
1036059Samurai  IpcpSendTerminateReq,
1046059Samurai  IpcpSendTerminateAck,
1056059Samurai  IpcpDecodeConfig,
1066059Samurai};
1076059Samurai
1086059Samuraistatic char *cftypes[] = {
1096059Samurai  "???", "IPADDRS", "COMPPROTO", "IPADDR",
1106059Samurai};
1116059Samurai
1126059Samurai/*
1136059Samurai * Function called every second. Updates connection period and idle period,
1146059Samurai * also update LQR information.
1156059Samurai */
1166059Samuraistatic void
1176059SamuraiIpcpReportFunc()
1186059Samurai{
1196059Samurai  ipConnectSecs++;
1206059Samurai  if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets)
1216059Samurai    ipIdleSecs++;
1226059Samurai  lastInOctets = ipInOctets;
1236059Samurai  lastOutOctets = ipOutOctets;
1246059Samurai  StopTimer(&IpcpReportTimer);
1256059Samurai  IpcpReportTimer.state = TIMER_STOPPED;
1266059Samurai  StartTimer(&IpcpReportTimer);
1276059Samurai}
1286059Samurai
1296059Samuraistatic void
1306059SamuraiIpcpStartReport()
1316059Samurai{
1326059Samurai  ipIdleSecs = ipConnectSecs = 0;
1336059Samurai  StopTimer(&IpcpReportTimer);
1346059Samurai  IpcpReportTimer.state = TIMER_STOPPED;
1356059Samurai  IpcpReportTimer.load = SECTICKS;
1366059Samurai  IpcpReportTimer.func = IpcpReportFunc;
1376059Samurai  StartTimer(&IpcpReportTimer);
1386059Samurai}
1396059Samurai
14025630Sbrianint
1416059SamuraiReportIpcpStatus()
1426059Samurai{
1436059Samurai  struct ipcpstate *icp = &IpcpInfo;
1446059Samurai  struct fsm *fp = &IpcpFsm;
1456059Samurai
14626516Sbrian  if (!VarTerm)
14726516Sbrian    return 1;
14826516Sbrian  fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
14926516Sbrian  fprintf(VarTerm, " his side: %s, %lx\n",
15028679Sbrian	  inet_ntoa(icp->his_ipaddr), icp->his_compproto);
15126516Sbrian  fprintf(VarTerm, " my  side: %s, %lx\n",
15228679Sbrian	  inet_ntoa(icp->want_ipaddr), icp->want_compproto);
15329048Sbrian  fprintf(VarTerm, "Connected: %d secs, idle: %d secs\n\n",
15429048Sbrian	  ipConnectSecs, ipIdleSecs);
15529048Sbrian  fprintf(VarTerm, " %d octets in, %d octets out\n",
15629048Sbrian	  IpcpOctetsIn(), IpcpOctetsOut());
15729048Sbrian
15826516Sbrian  fprintf(VarTerm, "Defaults:\n");
15926516Sbrian  fprintf(VarTerm, " My Address:  %s/%d\n",
16028679Sbrian	  inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width);
16126516Sbrian  fprintf(VarTerm, " His Address: %s/%d\n",
16228679Sbrian	  inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width);
16328394Sbrian  if (HaveTriggerAddress)
16428679Sbrian    fprintf(VarTerm, " Negotiation(trigger): %s\n", inet_ntoa(TriggerAddress));
16528394Sbrian  else
16628679Sbrian    fprintf(VarTerm, " Negotiation(trigger): MYADDR\n");
16726516Sbrian
16826516Sbrian  return 0;
1696059Samurai}
1706059Samurai
1716059Samuraivoid
1726059SamuraiIpcpDefAddress()
1736059Samurai{
1746059Samurai  struct hostent *hp;
1756059Samurai  char name[200];
1766059Samurai
17730715Sbrian  memset(&DefMyAddress, '\0', sizeof(DefMyAddress));
17830715Sbrian  memset(&DefHisAddress, '\0', sizeof(DefHisAddress));
17928394Sbrian  TriggerAddress.s_addr = 0;
18028394Sbrian  HaveTriggerAddress = 0;
1816059Samurai  if (gethostname(name, sizeof(name)) == 0) {
18228679Sbrian    hp = gethostbyname(name);
18328679Sbrian    if (hp && hp->h_addrtype == AF_INET) {
18430715Sbrian      memcpy(&DefMyAddress.ipaddr.s_addr, hp->h_addr, hp->h_length);
18528679Sbrian    }
1866059Samurai  }
1876059Samurai}
1886059Samurai
1896059Samuraivoid
1906059SamuraiIpcpInit()
1916059Samurai{
1926059Samurai  struct ipcpstate *icp = &IpcpInfo;
1936059Samurai
1946059Samurai  FsmInit(&IpcpFsm);
19530715Sbrian  memset(icp, '\0', sizeof(struct ipcpstate));
1966059Samurai  if ((mode & MODE_DEDICATED) && !dstsystem) {
1976059Samurai    icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0;
1986059Samurai  } else {
1996059Samurai    icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
2006059Samurai    icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
2016059Samurai  }
2029440Samurai
2039440Samurai  /*
20429048Sbrian   * Some implementations of PPP require that we send a
20529048Sbrian   * *special* value as our address, even though the rfc specifies
20629048Sbrian   * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
2079440Samurai   */
20828394Sbrian  if (HaveTriggerAddress) {
20928394Sbrian    icp->want_ipaddr.s_addr = TriggerAddress.s_addr;
21028461Sbrian    LogPrintf(LogIPCP, "Using trigger address %s\n", inet_ntoa(TriggerAddress));
2119440Samurai  }
2126059Samurai  if (Enabled(ConfVjcomp))
21330500Sbrian    icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8) | 1;
2146059Samurai  else
2156059Samurai    icp->want_compproto = 0;
2166059Samurai  icp->heis1172 = 0;
2176059Samurai  IpcpFsm.maxconfig = 10;
21829048Sbrian  StartingIpIn = ipInOctets;
21929048Sbrian  StartingIpOut = ipOutOctets;
2206059Samurai}
2216059Samurai
2226059Samuraistatic void
22328679SbrianIpcpInitRestartCounter(struct fsm * fp)
2246059Samurai{
2256735Samurai  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
2266059Samurai  fp->restart = 5;
2276059Samurai}
2286059Samurai
2296059Samuraistatic void
23028679SbrianIpcpSendConfigReq(struct fsm * fp)
2316059Samurai{
2326059Samurai  u_char *cp;
2336059Samurai  struct ipcpstate *icp = &IpcpInfo;
2346059Samurai
2356059Samurai  cp = ReqBuff;
23628461Sbrian  LogPrintf(LogIPCP, "IpcpSendConfigReq\n");
2376735Samurai  if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR))
2386735Samurai    PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr));
2396059Samurai  if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) {
2406059Samurai    if (icp->heis1172)
2416059Samurai      PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16);
2426059Samurai    else
2436059Samurai      PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto);
2446059Samurai  }
2456059Samurai  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
2466059Samurai}
2476059Samurai
2486059Samuraistatic void
24928679SbrianIpcpSendTerminateReq(struct fsm * fp)
2506059Samurai{
2516059Samurai  /* XXX: No code yet */
2526059Samurai}
2536059Samurai
2546059Samuraistatic void
25528679SbrianIpcpSendTerminateAck(struct fsm * fp)
2566059Samurai{
25728461Sbrian  LogPrintf(LogIPCP, "IpcpSendTerminateAck\n");
2586059Samurai  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
2596059Samurai}
2606059Samurai
2616059Samuraistatic void
26228679SbrianIpcpLayerStart(struct fsm * fp)
2636059Samurai{
26428461Sbrian  LogPrintf(LogIPCP, "IpcpLayerStart.\n");
2656059Samurai}
2666059Samurai
2676059Samuraistatic void
26828679SbrianIpcpLayerFinish(struct fsm * fp)
2696059Samurai{
27028461Sbrian  LogPrintf(LogIPCP, "IpcpLayerFinish.\n");
27126098Sbrian  reconnect(RECON_FALSE);
2726059Samurai  LcpClose();
2736059Samurai  NewPhase(PHASE_TERMINATE);
2746059Samurai}
2756059Samurai
27630715Sbrianstatic int
27729048SbrianIpcpOctetsIn()
27829048Sbrian{
27929048Sbrian  return ipInOctets < StartingIpIn ?
28029048Sbrian    INT_MAX - StartingIpIn + ipInOctets - INT_MIN + 1 :
28129048Sbrian    ipInOctets - StartingIpIn;
28229048Sbrian}
28329048Sbrian
28430715Sbrianstatic int
28529048SbrianIpcpOctetsOut()
28629048Sbrian{
28729048Sbrian  return ipOutOctets < StartingIpOut ?
28829048Sbrian    INT_MAX - StartingIpOut + ipOutOctets - INT_MIN + 1 :
28929048Sbrian    ipOutOctets - StartingIpOut;
29029048Sbrian}
29129048Sbrian
2926059Samuraistatic void
29328679SbrianIpcpLayerDown(struct fsm * fp)
2946059Samurai{
29528461Sbrian  LogPrintf(LogIPCP, "IpcpLayerDown.\n");
29629048Sbrian  LogPrintf(LogIPCP, "%d octets in, %d octets out\n",
29729048Sbrian	    IpcpOctetsIn(), IpcpOctetsOut());
2986059Samurai  StopTimer(&IpcpReportTimer);
29930825Sbrian  Prompt();
3006059Samurai}
3016059Samurai
3026059Samurai/*
3036059Samurai *  Called when IPCP has reached to OPEN state
3046059Samurai */
3056059Samuraistatic void
30628679SbrianIpcpLayerUp(struct fsm * fp)
3076059Samurai{
3086059Samurai  char tbuff[100];
3096059Samurai
31025630Sbrian  Prompt();
31128461Sbrian  LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state);
31228679Sbrian  snprintf(tbuff, sizeof(tbuff), "myaddr = %s ",
31328679Sbrian	   inet_ntoa(IpcpInfo.want_ipaddr));
31430187Sbrian
31530187Sbrian  if (IpcpInfo.his_compproto >> 16 == PROTO_VJCOMP)
31630187Sbrian    VjInit((IpcpInfo.his_compproto >> 8) & 255);
31730187Sbrian
31828461Sbrian  LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n",
31928679Sbrian	    tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
32025630Sbrian  if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask) < 0) {
32126516Sbrian    if (VarTerm)
32226516Sbrian      LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
32326516Sbrian    return;
32425630Sbrian  }
32527763Sbrian  if (mode & MODE_ALIAS)
32628679Sbrian    VarPacketAliasSetAddress(IpcpInfo.want_ipaddr);
3276059Samurai  OsLinkup();
32829048Sbrian  StartingIpIn = ipInOctets;
32929048Sbrian  StartingIpOut = ipOutOctets;
3306059Samurai  IpcpStartReport();
3316059Samurai  StartIdleTimer();
3326059Samurai}
3336059Samurai
3346059Samuraivoid
3356059SamuraiIpcpUp()
3366059Samurai{
3376059Samurai  FsmUp(&IpcpFsm);
33828461Sbrian  LogPrintf(LogIPCP, "IPCP Up event!!\n");
3396059Samurai}
3406059Samurai
3416059Samuraivoid
3426059SamuraiIpcpOpen()
3436059Samurai{
3446059Samurai  FsmOpen(&IpcpFsm);
3456059Samurai}
3466059Samurai
3476059Samuraistatic int
34828679SbrianAcceptableAddr(struct in_range * prange, struct in_addr ipaddr)
3496059Samurai{
35028974Sbrian  LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr));
35128974Sbrian  LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr));
35226516Sbrian  LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr));
35326516Sbrian  LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange->
35428679Sbrian		  mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr));
35525661Sbrian  return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
35628679Sbrian    (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
3576059Samurai}
3586059Samurai
3596059Samuraistatic void
36031034SbrianIpcpDecodeConfig(u_char * cp, int plen, int mode_type)
3616059Samurai{
3626735Samurai  int type, length;
3636059Samurai  u_long *lp, compproto;
3646059Samurai  struct compreq *pcomp;
36518752Sjkh  struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
3666059Samurai  char tbuff[100];
36721488Simp  char tbuff2[100];
3686059Samurai
3696059Samurai  ackp = AckBuff;
3706059Samurai  nakp = NakBuff;
3716059Samurai  rejp = RejBuff;
3726059Samurai
3736059Samurai  while (plen >= sizeof(struct fsmconfig)) {
3746059Samurai    type = *cp;
3756059Samurai    length = cp[1];
3766059Samurai    if (type <= TY_IPADDR)
37721488Simp      snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length);
3786059Samurai    else
37921488Simp      snprintf(tbuff, sizeof(tbuff), " ");
3806059Samurai
3816059Samurai    switch (type) {
3826059Samurai    case TY_IPADDR:		/* RFC1332 */
38328679Sbrian      lp = (u_long *) (cp + 2);
3846059Samurai      ipaddr.s_addr = *lp;
38528461Sbrian      LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
3866059Samurai
38731034Sbrian      switch (mode_type) {
3886059Samurai      case MODE_REQ:
3896059Samurai	if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
39028679Sbrian	  /*
39128679Sbrian	   * If destination address is not acceptable, insist to use what we
39228679Sbrian	   * want to use.
39328679Sbrian	   */
39430715Sbrian	  memcpy(nakp, cp, 2);
39530715Sbrian	  memcpy(nakp+2, &IpcpInfo.his_ipaddr.s_addr, length);
39628679Sbrian	  nakp += length;
39728679Sbrian	  break;
3986059Samurai	}
3996059Samurai	IpcpInfo.his_ipaddr = ipaddr;
40030715Sbrian	memcpy(ackp, cp, length);
4016059Samurai	ackp += length;
4026059Samurai	break;
4036059Samurai      case MODE_NAK:
4046059Samurai	if (AcceptableAddr(&DefMyAddress, ipaddr)) {
40528679Sbrian
40628679Sbrian	  /*
40728679Sbrian	   * Use address suggested by peer.
40828679Sbrian	   */
40928974Sbrian	  snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s ", tbuff,
41028974Sbrian		   inet_ntoa(IpcpInfo.want_ipaddr));
41128461Sbrian	  LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
4126059Samurai	  IpcpInfo.want_ipaddr = ipaddr;
4136059Samurai	}
4146059Samurai	break;
4156059Samurai      case MODE_REJ:
4166059Samurai	IpcpInfo.his_reject |= (1 << type);
4176059Samurai	break;
4186059Samurai      }
4196059Samurai      break;
4206059Samurai    case TY_COMPPROTO:
42128679Sbrian      lp = (u_long *) (cp + 2);
4226059Samurai      compproto = htonl(*lp);
42328461Sbrian      LogPrintf(LogIPCP, "%s %08x\n", tbuff, compproto);
4246059Samurai
42531034Sbrian      switch (mode_type) {
4266059Samurai      case MODE_REQ:
4276059Samurai	if (!Acceptable(ConfVjcomp)) {
42830715Sbrian	  memcpy(rejp, cp, length);
4296059Samurai	  rejp += length;
4306059Samurai	} else {
43128679Sbrian	  pcomp = (struct compreq *) (cp + 2);
4326059Samurai	  switch (length) {
43328679Sbrian	  case 4:		/* RFC1172 */
4346059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
43526940Sbrian	      LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
4366059Samurai	      IpcpInfo.heis1172 = 1;
4376059Samurai	      IpcpInfo.his_compproto = compproto;
43830715Sbrian	      memcpy(ackp, cp, length);
4396059Samurai	      ackp += length;
4406059Samurai	    } else {
44130715Sbrian	      memcpy(nakp, cp, 2);
4426059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
44330715Sbrian	      memcpy(nakp+2, &pcomp, 2);
4446059Samurai	      nakp += length;
4456059Samurai	    }
4466059Samurai	    break;
44728679Sbrian	  case 6:		/* RFC1332 */
4486059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
44928679Sbrian		&& pcomp->slots < MAX_STATES && pcomp->slots > 2) {
4506059Samurai	      IpcpInfo.his_compproto = compproto;
4516059Samurai	      IpcpInfo.heis1172 = 0;
45230715Sbrian	      memcpy(ackp, cp, length);
4536059Samurai	      ackp += length;
4546059Samurai	    } else {
45530715Sbrian	      memcpy(nakp, cp, 2);
4566059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
4576059Samurai	      pcomp->slots = MAX_STATES - 1;
4586059Samurai	      pcomp->compcid = 0;
45930715Sbrian	      memcpy(nakp+2, &pcomp, sizeof(pcomp));
4606059Samurai	      nakp += length;
4616059Samurai	    }
4626059Samurai	    break;
4636059Samurai	  default:
46430715Sbrian	    memcpy(rejp, cp, length);
4656059Samurai	    rejp += length;
4666059Samurai	    break;
4676059Samurai	  }
4686059Samurai	}
4696059Samurai	break;
4706059Samurai      case MODE_NAK:
47128461Sbrian	LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
47228679Sbrian		  tbuff, IpcpInfo.want_compproto, compproto);
4736059Samurai	IpcpInfo.want_compproto = compproto;
4746059Samurai	break;
4756059Samurai      case MODE_REJ:
4766059Samurai	IpcpInfo.his_reject |= (1 << type);
4776059Samurai	break;
4786059Samurai      }
4796059Samurai      break;
48028679Sbrian    case TY_IPADDRS:		/* RFC1172 */
48128679Sbrian      lp = (u_long *) (cp + 2);
4826059Samurai      ipaddr.s_addr = *lp;
48328679Sbrian      lp = (u_long *) (cp + 6);
4846059Samurai      dstipaddr.s_addr = *lp;
48528974Sbrian      snprintf(tbuff2, sizeof(tbuff2), "%s %s,", tbuff, inet_ntoa(ipaddr));
48628974Sbrian      LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
4876059Samurai
48831034Sbrian      switch (mode_type) {
4896059Samurai      case MODE_REQ:
4906059Samurai	IpcpInfo.his_ipaddr = ipaddr;
4916059Samurai	IpcpInfo.want_ipaddr = dstipaddr;
49230715Sbrian	memcpy(ackp, cp, length);
4936059Samurai	ackp += length;
4946059Samurai	break;
4956059Samurai      case MODE_NAK:
49628974Sbrian        snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s", tbuff,
49728974Sbrian		 inet_ntoa(IpcpInfo.want_ipaddr));
49828974Sbrian	LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
4996059Samurai	IpcpInfo.want_ipaddr = ipaddr;
5006059Samurai	IpcpInfo.his_ipaddr = dstipaddr;
5016059Samurai	break;
5026059Samurai      case MODE_REJ:
5036059Samurai	IpcpInfo.his_reject |= (1 << type);
5046059Samurai	break;
5056059Samurai      }
5066059Samurai      break;
50718752Sjkh
50828679Sbrian      /*
50928679Sbrian       * MS extensions for MS's PPP
51028679Sbrian       */
51118752Sjkh
51226516Sbrian#ifndef NOMSEXT
51328679Sbrian    case TY_PRIMARY_DNS:	/* MS PPP DNS negotiation hack */
51418752Sjkh    case TY_SECONDARY_DNS:
51528679Sbrian      if (!Enabled(ConfMSExt)) {
51628461Sbrian	LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n");
51728679Sbrian	IpcpInfo.my_reject |= (1 << type);
51830715Sbrian	memcpy(rejp, cp, length);
51918752Sjkh	rejp += length;
52018752Sjkh	break;
52118752Sjkh      }
52231034Sbrian      switch (mode_type) {
52318752Sjkh      case MODE_REQ:
52428679Sbrian	lp = (u_long *) (cp + 2);
52518752Sjkh	dnsstuff.s_addr = *lp;
52628679Sbrian	ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS) ? 1 : 0)].s_addr;
52728679Sbrian	if (dnsstuff.s_addr != ms_info_req.s_addr) {
52828679Sbrian
52918752Sjkh	  /*
53028679Sbrian	   * So the client has got the DNS stuff wrong (first request) so
53128974Sbrian	   * we'll tell 'em how it is
53228679Sbrian	   */
53330715Sbrian	  memcpy(nakp, cp, 2);	/* copy first two (type/length) */
53428679Sbrian	  LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n",
53528679Sbrian		    type,
53628679Sbrian		    inet_ntoa(dnsstuff),
53728679Sbrian		    inet_ntoa(ms_info_req));
53830715Sbrian	  memcpy(nakp+2, &ms_info_req, length);
53918752Sjkh	  nakp += length;
54018752Sjkh	  break;
54118752Sjkh	}
54228679Sbrian
54328679Sbrian	/*
54428679Sbrian	 * Otherwise they have it right (this time) so we send a ack packet
54528679Sbrian	 * back confirming it... end of story
54628679Sbrian	 */
54728679Sbrian	LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n",
54828679Sbrian		  type,
54928679Sbrian		  inet_ntoa(ms_info_req));
55030715Sbrian	memcpy(ackp, cp, length);
55118752Sjkh	ackp += length;
55218752Sjkh	break;
55328679Sbrian      case MODE_NAK:		/* what does this mean?? */
55428679Sbrian	LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type);
55518752Sjkh	break;
55628679Sbrian      case MODE_REJ:		/* confused?? me to :) */
55728679Sbrian	LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type);
55818752Sjkh	break;
55918752Sjkh      }
56018752Sjkh      break;
56118752Sjkh
56228679Sbrian    case TY_PRIMARY_NBNS:	/* MS PPP NetBIOS nameserver hack */
56318752Sjkh    case TY_SECONDARY_NBNS:
56428679Sbrian      if (!Enabled(ConfMSExt)) {
56528679Sbrian	LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n");
56628679Sbrian	IpcpInfo.my_reject |= (1 << type);
56730715Sbrian	memcpy(rejp, cp, length);
56828679Sbrian	rejp += length;
56928679Sbrian	break;
57028679Sbrian      }
57131034Sbrian      switch (mode_type) {
57218752Sjkh      case MODE_REQ:
57328679Sbrian	lp = (u_long *) (cp + 2);
57418752Sjkh	dnsstuff.s_addr = *lp;
57528679Sbrian	ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS) ? 1 : 0)].s_addr;
57628679Sbrian	if (dnsstuff.s_addr != ms_info_req.s_addr) {
57730715Sbrian	  memcpy(nakp, cp, 2);
57830715Sbrian	  memcpy(nakp+2, &ms_info_req.s_addr, length);
57928461Sbrian	  LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n",
58028679Sbrian		    type,
58128679Sbrian		    inet_ntoa(dnsstuff),
58228679Sbrian		    inet_ntoa(ms_info_req));
58318752Sjkh	  nakp += length;
58418752Sjkh	  break;
58518752Sjkh	}
58628461Sbrian	LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n",
58728679Sbrian		  type,
58828679Sbrian		  inet_ntoa(ms_info_req));
58930715Sbrian	memcpy(ackp, cp, length);
59018752Sjkh	ackp += length;
59118752Sjkh	break;
59218752Sjkh      case MODE_NAK:
59328679Sbrian	LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
59418752Sjkh	break;
59518752Sjkh      case MODE_REJ:
59628679Sbrian	LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
59718752Sjkh	break;
59818752Sjkh      }
59918752Sjkh      break;
60018752Sjkh
60126516Sbrian#endif
60218752Sjkh
6036059Samurai    default:
6046059Samurai      IpcpInfo.my_reject |= (1 << type);
60530715Sbrian      memcpy(rejp, cp, length);
6066059Samurai      rejp += length;
6076059Samurai      break;
6086059Samurai    }
6096059Samurai    plen -= length;
6106059Samurai    cp += length;
6116059Samurai  }
6126059Samurai}
6136059Samurai
6146059Samuraivoid
61528679SbrianIpcpInput(struct mbuf * bp)
6166059Samurai{
6176059Samurai  FsmInput(&IpcpFsm, bp);
6186059Samurai}
619