ipcp.c revision 31690
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 *
2031690Sbrian * $Id: ipcp.c,v 1.41 1997/12/06 22:43:58 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>
3631272Sbrian#include <time.h>
3730715Sbrian#include <unistd.h>
3830715Sbrian
3931343Sbrian#include "command.h"
4030715Sbrian#include "mbuf.h"
4130715Sbrian#include "log.h"
4230715Sbrian#include "defs.h"
4330715Sbrian#include "timer.h"
4429048Sbrian#include "fsm.h"
4529048Sbrian#include "lcpproto.h"
4629048Sbrian#include "lcp.h"
4731690Sbrian#include "iplist.h"
4829048Sbrian#include "ipcp.h"
496059Samurai#include "slcompress.h"
506059Samurai#include "os.h"
516059Samurai#include "phase.h"
5226142Sbrian#include "loadalias.h"
536059Samurai#include "vars.h"
5430715Sbrian#include "vjcomp.h"
5530733Sbrian#include "ip.h"
5631272Sbrian#include "throughput.h"
5731690Sbrian#include "route.h"
586059Samurai
5930715Sbrian#ifndef NOMSEXT
6030715Sbrianstruct in_addr ns_entries[2];
6130715Sbrianstruct in_addr nbns_entries[2];
6230715Sbrian#endif
636059Samurai
646059Samuraistruct ipcpstate IpcpInfo;
6530715Sbrianstruct in_range  DefMyAddress;
6630715Sbrianstruct in_range  DefHisAddress;
6731690Sbrianstruct iplist    DefHisChoice;
6830715Sbrianstruct in_addr   TriggerAddress;
6928394Sbrianint HaveTriggerAddress;
706059Samurai
7126516Sbrianstatic void IpcpSendConfigReq(struct fsm *);
7226516Sbrianstatic void IpcpSendTerminateAck(struct fsm *);
7326516Sbrianstatic void IpcpSendTerminateReq(struct fsm *);
7426516Sbrianstatic void IpcpDecodeConfig(u_char *, int, int);
7526516Sbrianstatic void IpcpLayerStart(struct fsm *);
7626516Sbrianstatic void IpcpLayerFinish(struct fsm *);
7726516Sbrianstatic void IpcpLayerUp(struct fsm *);
7826516Sbrianstatic void IpcpLayerDown(struct fsm *);
7926516Sbrianstatic void IpcpInitRestartCounter(struct fsm *);
806059Samurai
816059Samuraistruct fsm IpcpFsm = {
826059Samurai  "IPCP",
836059Samurai  PROTO_IPCP,
846059Samurai  IPCP_MAXCODE,
856059Samurai  OPEN_ACTIVE,
866059Samurai  ST_INITIAL,
876059Samurai  0, 0, 0,
886059Samurai
896059Samurai  0,
9028679Sbrian  {0, 0, 0, NULL, NULL, NULL},
9128679Sbrian  {0, 0, 0, NULL, NULL, NULL},
9228461Sbrian  LogIPCP,
936059Samurai
946059Samurai  IpcpLayerUp,
956059Samurai  IpcpLayerDown,
966059Samurai  IpcpLayerStart,
976059Samurai  IpcpLayerFinish,
986059Samurai  IpcpInitRestartCounter,
996059Samurai  IpcpSendConfigReq,
1006059Samurai  IpcpSendTerminateReq,
1016059Samurai  IpcpSendTerminateAck,
1026059Samurai  IpcpDecodeConfig,
1036059Samurai};
1046059Samurai
10531343Sbrianstatic const char *cftypes[] = {
10631171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
10731171Sbrian  "???",
10831171Sbrian  "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
10931171Sbrian  "COMPPROTO",	/* 2: IP-Compression-Protocol */
11031171Sbrian  "IPADDR",	/* 3: IP-Address */
1116059Samurai};
1126059Samurai
11331171Sbrian#define NCFTYPES (sizeof(cftypes)/sizeof(char *))
11431171Sbrian
11531343Sbrianstatic const char *cftypes128[] = {
11631171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
11731171Sbrian  "???",
11831171Sbrian  "PRIDNS",	/* 129: Primary DNS Server Address */
11931171Sbrian  "PRINBNS",	/* 130: Primary NBNS Server Address */
12031171Sbrian  "SECDNS",	/* 131: Secondary DNS Server Address */
12131171Sbrian  "SECNBNS",	/* 132: Secondary NBNS Server Address */
12231171Sbrian};
12331171Sbrian
12431171Sbrian#define NCFTYPES128 (sizeof(cftypes)/sizeof(char *))
12531171Sbrian
12631272Sbrianstruct pppThroughput throughput;
12731272Sbrian
12831272Sbrianvoid
12931272SbrianIpcpAddInOctets(int n)
1306059Samurai{
13131272Sbrian  throughput_addin(&throughput, n);
1326059Samurai}
1336059Samurai
13431272Sbrianvoid
13531272SbrianIpcpAddOutOctets(int n)
1366059Samurai{
13731272Sbrian  throughput_addout(&throughput, n);
1386059Samurai}
1396059Samurai
14025630Sbrianint
14131343SbrianReportIpcpStatus(struct cmdargs const *arg)
1426059Samurai{
1436059Samurai  struct fsm *fp = &IpcpFsm;
1446059Samurai
14526516Sbrian  if (!VarTerm)
14626516Sbrian    return 1;
14726516Sbrian  fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]);
14831514Sbrian  fprintf(VarTerm, " his side: %s, %s\n",
14931540Sbrian	  inet_ntoa(IpcpInfo.his_ipaddr), vj2asc(IpcpInfo.his_compproto));
15031514Sbrian  fprintf(VarTerm, " my  side: %s, %s\n",
15131540Sbrian	  inet_ntoa(IpcpInfo.want_ipaddr), vj2asc(IpcpInfo.want_compproto));
15229048Sbrian
15326516Sbrian  fprintf(VarTerm, "Defaults:\n");
15426516Sbrian  fprintf(VarTerm, " My Address:  %s/%d\n",
15528679Sbrian	  inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width);
15626516Sbrian  fprintf(VarTerm, " His Address: %s/%d\n",
15728679Sbrian	  inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width);
15828394Sbrian  if (HaveTriggerAddress)
15928679Sbrian    fprintf(VarTerm, " Negotiation(trigger): %s\n", inet_ntoa(TriggerAddress));
16028394Sbrian  else
16128679Sbrian    fprintf(VarTerm, " Negotiation(trigger): MYADDR\n");
16226516Sbrian
16331272Sbrian  fprintf(VarTerm, "\n");
16431272Sbrian  throughput_disp(&throughput, VarTerm);
16531272Sbrian
16626516Sbrian  return 0;
1676059Samurai}
1686059Samurai
1696059Samuraivoid
1706059SamuraiIpcpDefAddress()
1716059Samurai{
1726059Samurai  struct hostent *hp;
1736059Samurai  char name[200];
1746059Samurai
17530715Sbrian  memset(&DefMyAddress, '\0', sizeof(DefMyAddress));
17630715Sbrian  memset(&DefHisAddress, '\0', sizeof(DefHisAddress));
17728394Sbrian  TriggerAddress.s_addr = 0;
17828394Sbrian  HaveTriggerAddress = 0;
1796059Samurai  if (gethostname(name, sizeof(name)) == 0) {
18028679Sbrian    hp = gethostbyname(name);
18128679Sbrian    if (hp && hp->h_addrtype == AF_INET) {
18230715Sbrian      memcpy(&DefMyAddress.ipaddr.s_addr, hp->h_addr, hp->h_length);
18328679Sbrian    }
1846059Samurai  }
1856059Samurai}
1866059Samurai
1876059Samuraivoid
1886059SamuraiIpcpInit()
1896059Samurai{
19031690Sbrian  if (iplist_isvalid(&DefHisChoice))
19131690Sbrian    iplist_setrandpos(&DefHisChoice);
1926059Samurai  FsmInit(&IpcpFsm);
19331540Sbrian  memset(&IpcpInfo, '\0', sizeof(struct ipcpstate));
19431121Sbrian  if ((mode & MODE_DEDICATED) && !GetLabel()) {
19531540Sbrian    IpcpInfo.want_ipaddr.s_addr = IpcpInfo.his_ipaddr.s_addr = 0;
1966059Samurai  } else {
19731540Sbrian    IpcpInfo.want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
19831540Sbrian    IpcpInfo.his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
1996059Samurai  }
2009440Samurai
2019440Samurai  /*
20229048Sbrian   * Some implementations of PPP require that we send a
20329048Sbrian   * *special* value as our address, even though the rfc specifies
20429048Sbrian   * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
2059440Samurai   */
20628394Sbrian  if (HaveTriggerAddress) {
20731540Sbrian    IpcpInfo.want_ipaddr.s_addr = TriggerAddress.s_addr;
20828461Sbrian    LogPrintf(LogIPCP, "Using trigger address %s\n", inet_ntoa(TriggerAddress));
2099440Samurai  }
2106059Samurai  if (Enabled(ConfVjcomp))
21131540Sbrian    IpcpInfo.want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8) | 1;
2126059Samurai  else
21331540Sbrian    IpcpInfo.want_compproto = 0;
21431540Sbrian  IpcpInfo.heis1172 = 0;
2156059Samurai  IpcpFsm.maxconfig = 10;
21631272Sbrian  throughput_init(&throughput);
2176059Samurai}
2186059Samurai
2196059Samuraistatic void
22028679SbrianIpcpInitRestartCounter(struct fsm * fp)
2216059Samurai{
2226735Samurai  fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
2236059Samurai  fp->restart = 5;
2246059Samurai}
2256059Samurai
2266059Samuraistatic void
22728679SbrianIpcpSendConfigReq(struct fsm * fp)
2286059Samurai{
2296059Samurai  u_char *cp;
23031514Sbrian  struct lcp_opt o;
2316059Samurai
2326059Samurai  cp = ReqBuff;
23328461Sbrian  LogPrintf(LogIPCP, "IpcpSendConfigReq\n");
23431540Sbrian  if (!DEV_IS_SYNC || !REJECTED(&IpcpInfo, TY_IPADDR)) {
23531514Sbrian    o.id = TY_IPADDR;
23631514Sbrian    o.len = 6;
23731540Sbrian    *(u_long *)o.data = IpcpInfo.want_ipaddr.s_addr;
23831514Sbrian    cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id],
23931540Sbrian                     inet_ntoa(IpcpInfo.want_ipaddr));
24031514Sbrian  }
24131514Sbrian
24231540Sbrian  if (IpcpInfo.want_compproto && !REJECTED(&IpcpInfo, TY_COMPPROTO)) {
24331514Sbrian    const char *args;
24431514Sbrian    o.id = TY_COMPPROTO;
24531540Sbrian    if (IpcpInfo.heis1172) {
24631514Sbrian      o.len = 4;
24731514Sbrian      *(u_short *)o.data = htons(PROTO_VJCOMP);
24831514Sbrian      args = "";
24931514Sbrian    } else {
25031514Sbrian      o.len = 6;
25131540Sbrian      *(u_long *)o.data = htonl(IpcpInfo.want_compproto);
25231540Sbrian      args = vj2asc(IpcpInfo.want_compproto);
25331514Sbrian    }
25431514Sbrian    cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], args);
2556059Samurai  }
2566059Samurai  FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
2576059Samurai}
2586059Samurai
2596059Samuraistatic void
26028679SbrianIpcpSendTerminateReq(struct fsm * fp)
2616059Samurai{
2626059Samurai  /* XXX: No code yet */
2636059Samurai}
2646059Samurai
2656059Samuraistatic void
26628679SbrianIpcpSendTerminateAck(struct fsm * fp)
2676059Samurai{
26828461Sbrian  LogPrintf(LogIPCP, "IpcpSendTerminateAck\n");
2696059Samurai  FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
2706059Samurai}
2716059Samurai
2726059Samuraistatic void
27328679SbrianIpcpLayerStart(struct fsm * fp)
2746059Samurai{
27528461Sbrian  LogPrintf(LogIPCP, "IpcpLayerStart.\n");
2766059Samurai}
2776059Samurai
2786059Samuraistatic void
27928679SbrianIpcpLayerFinish(struct fsm * fp)
2806059Samurai{
28128461Sbrian  LogPrintf(LogIPCP, "IpcpLayerFinish.\n");
28226098Sbrian  reconnect(RECON_FALSE);
2836059Samurai  LcpClose();
2846059Samurai  NewPhase(PHASE_TERMINATE);
2856059Samurai}
2866059Samurai
2876059Samuraistatic void
28828679SbrianIpcpLayerDown(struct fsm * fp)
2896059Samurai{
29028461Sbrian  LogPrintf(LogIPCP, "IpcpLayerDown.\n");
29131272Sbrian  throughput_stop(&throughput);
29231272Sbrian  throughput_log(&throughput, LogIPCP, NULL);
2936059Samurai}
2946059Samurai
2956059Samurai/*
2966059Samurai *  Called when IPCP has reached to OPEN state
2976059Samurai */
2986059Samuraistatic void
29928679SbrianIpcpLayerUp(struct fsm * fp)
3006059Samurai{
3016059Samurai  char tbuff[100];
3026059Samurai
30325630Sbrian  Prompt();
30428461Sbrian  LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state);
30528679Sbrian  snprintf(tbuff, sizeof(tbuff), "myaddr = %s ",
30628679Sbrian	   inet_ntoa(IpcpInfo.want_ipaddr));
30730187Sbrian
30830187Sbrian  if (IpcpInfo.his_compproto >> 16 == PROTO_VJCOMP)
30930187Sbrian    VjInit((IpcpInfo.his_compproto >> 8) & 255);
31030187Sbrian
31128461Sbrian  LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n",
31228679Sbrian	    tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
31331690Sbrian  if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr) < 0) {
31426516Sbrian    if (VarTerm)
31526516Sbrian      LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
31626516Sbrian    return;
31725630Sbrian  }
31831343Sbrian#ifndef NOALIAS
31927763Sbrian  if (mode & MODE_ALIAS)
32028679Sbrian    VarPacketAliasSetAddress(IpcpInfo.want_ipaddr);
32131343Sbrian#endif
3226059Samurai  OsLinkup();
32331272Sbrian  throughput_start(&throughput);
3246059Samurai  StartIdleTimer();
3256059Samurai}
3266059Samurai
3276059Samuraivoid
3286059SamuraiIpcpUp()
3296059Samurai{
3306059Samurai  FsmUp(&IpcpFsm);
33128461Sbrian  LogPrintf(LogIPCP, "IPCP Up event!!\n");
3326059Samurai}
3336059Samurai
3346059Samuraivoid
3356059SamuraiIpcpOpen()
3366059Samurai{
3376059Samurai  FsmOpen(&IpcpFsm);
3386059Samurai}
3396059Samurai
3406059Samuraistatic int
34128679SbrianAcceptableAddr(struct in_range * prange, struct in_addr ipaddr)
3426059Samurai{
34328974Sbrian  LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr));
34428974Sbrian  LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr));
34526516Sbrian  LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr));
34626516Sbrian  LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange->
34728679Sbrian		  mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr));
34825661Sbrian  return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
34928679Sbrian    (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
3506059Samurai}
3516059Samurai
3526059Samuraistatic void
35331034SbrianIpcpDecodeConfig(u_char * cp, int plen, int mode_type)
3546059Samurai{
3556735Samurai  int type, length;
3566059Samurai  u_long *lp, compproto;
3576059Samurai  struct compreq *pcomp;
35818752Sjkh  struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
3596059Samurai  char tbuff[100];
36021488Simp  char tbuff2[100];
3616059Samurai
3626059Samurai  ackp = AckBuff;
3636059Samurai  nakp = NakBuff;
3646059Samurai  rejp = RejBuff;
3656059Samurai
3666059Samurai  while (plen >= sizeof(struct fsmconfig)) {
3676059Samurai    type = *cp;
3686059Samurai    length = cp[1];
36931171Sbrian    if (type < NCFTYPES)
37021488Simp      snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length);
37131171Sbrian    else if (type > 128 && type < 128 + NCFTYPES128)
37231585Sbrian      snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes128[type-128], length);
3736059Samurai    else
37431690Sbrian      snprintf(tbuff, sizeof(tbuff), " <%d>[%d] ", type, length);
3756059Samurai
3766059Samurai    switch (type) {
3776059Samurai    case TY_IPADDR:		/* RFC1332 */
37828679Sbrian      lp = (u_long *) (cp + 2);
3796059Samurai      ipaddr.s_addr = *lp;
38028461Sbrian      LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
3816059Samurai
38231034Sbrian      switch (mode_type) {
3836059Samurai      case MODE_REQ:
38431690Sbrian        if (iplist_isvalid(&DefHisChoice)) {
38531690Sbrian          if (iplist_ip2pos(&DefHisChoice, ipaddr) < 0 ||
38631690Sbrian              OsTrySetIpaddress(DefMyAddress.ipaddr, ipaddr) != 0) {
38731690Sbrian            LogPrintf(LogIPCP, "%s: Address invalid or already in use\n",
38831690Sbrian                      inet_ntoa(ipaddr));
38931690Sbrian            IpcpInfo.his_ipaddr = ChooseHisAddr(DefMyAddress.ipaddr);
39031690Sbrian            if (IpcpInfo.his_ipaddr.s_addr == INADDR_ANY) {
39131690Sbrian	      memcpy(rejp, cp, length);
39231690Sbrian	      rejp += length;
39331690Sbrian            } else {
39431690Sbrian	      memcpy(nakp, cp, 2);
39531690Sbrian	      memcpy(nakp+2, &IpcpInfo.his_ipaddr.s_addr, length - 2);
39631690Sbrian	      nakp += length;
39731690Sbrian            }
39831690Sbrian	    break;
39931690Sbrian          }
40031690Sbrian	} else if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
40128679Sbrian	  /*
40228679Sbrian	   * If destination address is not acceptable, insist to use what we
40328679Sbrian	   * want to use.
40428679Sbrian	   */
40530715Sbrian	  memcpy(nakp, cp, 2);
40631690Sbrian	  memcpy(nakp+2, &IpcpInfo.his_ipaddr.s_addr, length - 2);
40728679Sbrian	  nakp += length;
40828679Sbrian	  break;
4096059Samurai	}
4106059Samurai	IpcpInfo.his_ipaddr = ipaddr;
41130715Sbrian	memcpy(ackp, cp, length);
4126059Samurai	ackp += length;
4136059Samurai	break;
4146059Samurai      case MODE_NAK:
4156059Samurai	if (AcceptableAddr(&DefMyAddress, ipaddr)) {
41631690Sbrian	  /* Use address suggested by peer */
41728974Sbrian	  snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s ", tbuff,
41828974Sbrian		   inet_ntoa(IpcpInfo.want_ipaddr));
41928461Sbrian	  LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
4206059Samurai	  IpcpInfo.want_ipaddr = ipaddr;
42131690Sbrian	} else {
42231690Sbrian	  LogPrintf(LogIPCP, "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
42331690Sbrian          FsmClose(&IpcpFsm);
4246059Samurai	}
4256059Samurai	break;
4266059Samurai      case MODE_REJ:
4276059Samurai	IpcpInfo.his_reject |= (1 << type);
4286059Samurai	break;
4296059Samurai      }
4306059Samurai      break;
4316059Samurai    case TY_COMPPROTO:
43228679Sbrian      lp = (u_long *) (cp + 2);
4336059Samurai      compproto = htonl(*lp);
43431514Sbrian      LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
4356059Samurai
43631034Sbrian      switch (mode_type) {
4376059Samurai      case MODE_REQ:
4386059Samurai	if (!Acceptable(ConfVjcomp)) {
43930715Sbrian	  memcpy(rejp, cp, length);
4406059Samurai	  rejp += length;
4416059Samurai	} else {
44228679Sbrian	  pcomp = (struct compreq *) (cp + 2);
4436059Samurai	  switch (length) {
44428679Sbrian	  case 4:		/* RFC1172 */
4456059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
44626940Sbrian	      LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
4476059Samurai	      IpcpInfo.heis1172 = 1;
4486059Samurai	      IpcpInfo.his_compproto = compproto;
44930715Sbrian	      memcpy(ackp, cp, length);
4506059Samurai	      ackp += length;
4516059Samurai	    } else {
45230715Sbrian	      memcpy(nakp, cp, 2);
4536059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
45430715Sbrian	      memcpy(nakp+2, &pcomp, 2);
4556059Samurai	      nakp += length;
4566059Samurai	    }
4576059Samurai	    break;
45828679Sbrian	  case 6:		/* RFC1332 */
4596059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
46028679Sbrian		&& pcomp->slots < MAX_STATES && pcomp->slots > 2) {
4616059Samurai	      IpcpInfo.his_compproto = compproto;
4626059Samurai	      IpcpInfo.heis1172 = 0;
46330715Sbrian	      memcpy(ackp, cp, length);
4646059Samurai	      ackp += length;
4656059Samurai	    } else {
46630715Sbrian	      memcpy(nakp, cp, 2);
4676059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
4686059Samurai	      pcomp->slots = MAX_STATES - 1;
4696059Samurai	      pcomp->compcid = 0;
47030715Sbrian	      memcpy(nakp+2, &pcomp, sizeof(pcomp));
4716059Samurai	      nakp += length;
4726059Samurai	    }
4736059Samurai	    break;
4746059Samurai	  default:
47530715Sbrian	    memcpy(rejp, cp, length);
4766059Samurai	    rejp += length;
4776059Samurai	    break;
4786059Samurai	  }
4796059Samurai	}
4806059Samurai	break;
4816059Samurai      case MODE_NAK:
48228461Sbrian	LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
48328679Sbrian		  tbuff, IpcpInfo.want_compproto, compproto);
4846059Samurai	IpcpInfo.want_compproto = compproto;
4856059Samurai	break;
4866059Samurai      case MODE_REJ:
4876059Samurai	IpcpInfo.his_reject |= (1 << type);
4886059Samurai	break;
4896059Samurai      }
4906059Samurai      break;
49128679Sbrian    case TY_IPADDRS:		/* RFC1172 */
49228679Sbrian      lp = (u_long *) (cp + 2);
4936059Samurai      ipaddr.s_addr = *lp;
49428679Sbrian      lp = (u_long *) (cp + 6);
4956059Samurai      dstipaddr.s_addr = *lp;
49628974Sbrian      snprintf(tbuff2, sizeof(tbuff2), "%s %s,", tbuff, inet_ntoa(ipaddr));
49728974Sbrian      LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
4986059Samurai
49931034Sbrian      switch (mode_type) {
5006059Samurai      case MODE_REQ:
5016059Samurai	IpcpInfo.his_ipaddr = ipaddr;
5026059Samurai	IpcpInfo.want_ipaddr = dstipaddr;
50330715Sbrian	memcpy(ackp, cp, length);
5046059Samurai	ackp += length;
5056059Samurai	break;
5066059Samurai      case MODE_NAK:
50728974Sbrian        snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s", tbuff,
50828974Sbrian		 inet_ntoa(IpcpInfo.want_ipaddr));
50928974Sbrian	LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
5106059Samurai	IpcpInfo.want_ipaddr = ipaddr;
5116059Samurai	IpcpInfo.his_ipaddr = dstipaddr;
5126059Samurai	break;
5136059Samurai      case MODE_REJ:
5146059Samurai	IpcpInfo.his_reject |= (1 << type);
5156059Samurai	break;
5166059Samurai      }
5176059Samurai      break;
51818752Sjkh
51928679Sbrian      /*
52028679Sbrian       * MS extensions for MS's PPP
52128679Sbrian       */
52218752Sjkh
52326516Sbrian#ifndef NOMSEXT
52428679Sbrian    case TY_PRIMARY_DNS:	/* MS PPP DNS negotiation hack */
52518752Sjkh    case TY_SECONDARY_DNS:
52628679Sbrian      if (!Enabled(ConfMSExt)) {
52728461Sbrian	LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n");
52828679Sbrian	IpcpInfo.my_reject |= (1 << type);
52930715Sbrian	memcpy(rejp, cp, length);
53018752Sjkh	rejp += length;
53118752Sjkh	break;
53218752Sjkh      }
53331034Sbrian      switch (mode_type) {
53418752Sjkh      case MODE_REQ:
53528679Sbrian	lp = (u_long *) (cp + 2);
53618752Sjkh	dnsstuff.s_addr = *lp;
53728679Sbrian	ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS) ? 1 : 0)].s_addr;
53828679Sbrian	if (dnsstuff.s_addr != ms_info_req.s_addr) {
53928679Sbrian
54018752Sjkh	  /*
54128679Sbrian	   * So the client has got the DNS stuff wrong (first request) so
54228974Sbrian	   * we'll tell 'em how it is
54328679Sbrian	   */
54430715Sbrian	  memcpy(nakp, cp, 2);	/* copy first two (type/length) */
54528679Sbrian	  LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n",
54628679Sbrian		    type,
54728679Sbrian		    inet_ntoa(dnsstuff),
54828679Sbrian		    inet_ntoa(ms_info_req));
54930715Sbrian	  memcpy(nakp+2, &ms_info_req, length);
55018752Sjkh	  nakp += length;
55118752Sjkh	  break;
55218752Sjkh	}
55328679Sbrian
55428679Sbrian	/*
55528679Sbrian	 * Otherwise they have it right (this time) so we send a ack packet
55628679Sbrian	 * back confirming it... end of story
55728679Sbrian	 */
55828679Sbrian	LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n",
55928679Sbrian		  type,
56028679Sbrian		  inet_ntoa(ms_info_req));
56130715Sbrian	memcpy(ackp, cp, length);
56218752Sjkh	ackp += length;
56318752Sjkh	break;
56428679Sbrian      case MODE_NAK:		/* what does this mean?? */
56528679Sbrian	LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type);
56618752Sjkh	break;
56728679Sbrian      case MODE_REJ:		/* confused?? me to :) */
56828679Sbrian	LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type);
56918752Sjkh	break;
57018752Sjkh      }
57118752Sjkh      break;
57218752Sjkh
57328679Sbrian    case TY_PRIMARY_NBNS:	/* MS PPP NetBIOS nameserver hack */
57418752Sjkh    case TY_SECONDARY_NBNS:
57528679Sbrian      if (!Enabled(ConfMSExt)) {
57628679Sbrian	LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n");
57728679Sbrian	IpcpInfo.my_reject |= (1 << type);
57830715Sbrian	memcpy(rejp, cp, length);
57928679Sbrian	rejp += length;
58028679Sbrian	break;
58128679Sbrian      }
58231034Sbrian      switch (mode_type) {
58318752Sjkh      case MODE_REQ:
58428679Sbrian	lp = (u_long *) (cp + 2);
58518752Sjkh	dnsstuff.s_addr = *lp;
58628679Sbrian	ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS) ? 1 : 0)].s_addr;
58728679Sbrian	if (dnsstuff.s_addr != ms_info_req.s_addr) {
58830715Sbrian	  memcpy(nakp, cp, 2);
58930715Sbrian	  memcpy(nakp+2, &ms_info_req.s_addr, length);
59028461Sbrian	  LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n",
59128679Sbrian		    type,
59228679Sbrian		    inet_ntoa(dnsstuff),
59328679Sbrian		    inet_ntoa(ms_info_req));
59418752Sjkh	  nakp += length;
59518752Sjkh	  break;
59618752Sjkh	}
59728461Sbrian	LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n",
59828679Sbrian		  type,
59928679Sbrian		  inet_ntoa(ms_info_req));
60030715Sbrian	memcpy(ackp, cp, length);
60118752Sjkh	ackp += length;
60218752Sjkh	break;
60318752Sjkh      case MODE_NAK:
60428679Sbrian	LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
60518752Sjkh	break;
60618752Sjkh      case MODE_REJ:
60728679Sbrian	LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
60818752Sjkh	break;
60918752Sjkh      }
61018752Sjkh      break;
61118752Sjkh
61226516Sbrian#endif
61318752Sjkh
6146059Samurai    default:
6156059Samurai      IpcpInfo.my_reject |= (1 << type);
61630715Sbrian      memcpy(rejp, cp, length);
6176059Samurai      rejp += length;
6186059Samurai      break;
6196059Samurai    }
6206059Samurai    plen -= length;
6216059Samurai    cp += length;
6226059Samurai  }
6236059Samurai}
6246059Samurai
6256059Samuraivoid
62628679SbrianIpcpInput(struct mbuf * bp)
6276059Samurai{
6286059Samurai  FsmInput(&IpcpFsm, bp);
6296059Samurai}
630