xref: /freebsd/usr.sbin/ppp/ipcp.c (revision 455aabc3f8ec34f01e0c38a52775d8fad9b7b55c)
11ae349f5Scvs2svn /*
21ae349f5Scvs2svn  *	PPP IP Control Protocol (IPCP) Module
31ae349f5Scvs2svn  *
41ae349f5Scvs2svn  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
51ae349f5Scvs2svn  *
61ae349f5Scvs2svn  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
71ae349f5Scvs2svn  *
81ae349f5Scvs2svn  * Redistribution and use in source and binary forms are permitted
91ae349f5Scvs2svn  * provided that the above copyright notice and this paragraph are
101ae349f5Scvs2svn  * duplicated in all such forms and that any documentation,
111ae349f5Scvs2svn  * advertising materials, and other materials related to such
121ae349f5Scvs2svn  * distribution and use acknowledge that the software was developed
131ae349f5Scvs2svn  * by the Internet Initiative Japan, Inc.  The name of the
141ae349f5Scvs2svn  * IIJ may not be used to endorse or promote products derived
151ae349f5Scvs2svn  * from this software without specific prior written permission.
161ae349f5Scvs2svn  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171ae349f5Scvs2svn  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181ae349f5Scvs2svn  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191ae349f5Scvs2svn  *
20455aabc3SBrian Somers  * $Id: ipcp.c,v 1.50.2.8 1998/02/06 02:24:19 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  *	TODO:
231ae349f5Scvs2svn  *		o More RFC1772 backwoard compatibility
241ae349f5Scvs2svn  */
251ae349f5Scvs2svn #include <sys/param.h>
261ae349f5Scvs2svn #include <netinet/in_systm.h>
271ae349f5Scvs2svn #include <netinet/in.h>
281ae349f5Scvs2svn #include <netinet/ip.h>
291ae349f5Scvs2svn #include <arpa/inet.h>
301ae349f5Scvs2svn #include <sys/socket.h>
311ae349f5Scvs2svn #include <netdb.h>
32455aabc3SBrian Somers #include <sys/time.h>
33455aabc3SBrian Somers #include <net/if.h>
34455aabc3SBrian Somers #include <sys/sockio.h>
351ae349f5Scvs2svn 
361ae349f5Scvs2svn #include <stdio.h>
371ae349f5Scvs2svn #include <stdlib.h>
381ae349f5Scvs2svn #include <string.h>
39455aabc3SBrian Somers #include <sys/errno.h>
406140ba11SBrian Somers #include <termios.h>
411ae349f5Scvs2svn #include <unistd.h>
421ae349f5Scvs2svn 
431ae349f5Scvs2svn #include "command.h"
441ae349f5Scvs2svn #include "mbuf.h"
451ae349f5Scvs2svn #include "log.h"
461ae349f5Scvs2svn #include "defs.h"
471ae349f5Scvs2svn #include "timer.h"
481ae349f5Scvs2svn #include "fsm.h"
491ae349f5Scvs2svn #include "lcpproto.h"
501ae349f5Scvs2svn #include "lcp.h"
511ae349f5Scvs2svn #include "iplist.h"
5229e275ceSBrian Somers #include "throughput.h"
531ae349f5Scvs2svn #include "ipcp.h"
541ae349f5Scvs2svn #include "slcompress.h"
557a6f8720SBrian Somers #include "bundle.h"
561ae349f5Scvs2svn #include "loadalias.h"
571ae349f5Scvs2svn #include "vars.h"
581ae349f5Scvs2svn #include "vjcomp.h"
591ae349f5Scvs2svn #include "ip.h"
601ae349f5Scvs2svn #include "route.h"
611ae349f5Scvs2svn #include "filter.h"
628c07a7b2SBrian Somers #include "hdlc.h"
636140ba11SBrian Somers #include "async.h"
648c07a7b2SBrian Somers #include "link.h"
6563b73463SBrian Somers #include "physical.h"
66455aabc3SBrian Somers #include "id.h"
67455aabc3SBrian Somers #include "arp.h"
68455aabc3SBrian Somers #include "systems.h"
691ae349f5Scvs2svn 
7029e275ceSBrian Somers struct compreq {
7129e275ceSBrian Somers   u_short proto;
7229e275ceSBrian Somers   u_char slots;
7329e275ceSBrian Somers   u_char compcid;
7429e275ceSBrian Somers };
751ae349f5Scvs2svn 
761ae349f5Scvs2svn static void IpcpLayerUp(struct fsm *);
771ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *);
787308ec68SBrian Somers static void IpcpLayerStart(struct fsm *);
797308ec68SBrian Somers static void IpcpLayerFinish(struct fsm *);
801ae349f5Scvs2svn static void IpcpInitRestartCounter(struct fsm *);
817308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *);
827308ec68SBrian Somers static void IpcpSendTerminateReq(struct fsm *);
837308ec68SBrian Somers static void IpcpSendTerminateAck(struct fsm *);
8483d1af55SBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int);
8583d1af55SBrian Somers 
8683d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = {
8783d1af55SBrian Somers   IpcpLayerUp,
8883d1af55SBrian Somers   IpcpLayerDown,
8983d1af55SBrian Somers   IpcpLayerStart,
9083d1af55SBrian Somers   IpcpLayerFinish,
9183d1af55SBrian Somers   IpcpInitRestartCounter,
9283d1af55SBrian Somers   IpcpSendConfigReq,
9383d1af55SBrian Somers   IpcpSendTerminateReq,
9483d1af55SBrian Somers   IpcpSendTerminateAck,
9583d1af55SBrian Somers   IpcpDecodeConfig,
9683d1af55SBrian Somers };
971ae349f5Scvs2svn 
987308ec68SBrian Somers struct ipcpstate IpcpInfo = {
997308ec68SBrian Somers   {
1001ae349f5Scvs2svn     "IPCP",
1011ae349f5Scvs2svn     PROTO_IPCP,
1021ae349f5Scvs2svn     IPCP_MAXCODE,
1031ae349f5Scvs2svn     0,
1041ae349f5Scvs2svn     ST_INITIAL,
1051ae349f5Scvs2svn     0, 0, 0,
1061ae349f5Scvs2svn     {0, 0, 0, NULL, NULL, NULL},	/* FSM timer */
1071ae349f5Scvs2svn     {0, 0, 0, NULL, NULL, NULL},	/* Open timer */
1081ae349f5Scvs2svn     {0, 0, 0, NULL, NULL, NULL},	/* Stopped timer */
1091ae349f5Scvs2svn     LogIPCP,
1107a6f8720SBrian Somers     NULL,				/* link */
1117a6f8720SBrian Somers     NULL,				/* bundle */
11283d1af55SBrian Somers     &ipcp_Callbacks,
1137308ec68SBrian Somers   },
1147308ec68SBrian Somers   MAX_VJ_STATES,
1157308ec68SBrian Somers   1
1161ae349f5Scvs2svn };
1171ae349f5Scvs2svn 
1181ae349f5Scvs2svn static const char *cftypes[] = {
1191ae349f5Scvs2svn   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1201ae349f5Scvs2svn   "???",
1211ae349f5Scvs2svn   "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
1221ae349f5Scvs2svn   "COMPPROTO",	/* 2: IP-Compression-Protocol */
1231ae349f5Scvs2svn   "IPADDR",	/* 3: IP-Address */
1241ae349f5Scvs2svn };
1251ae349f5Scvs2svn 
1261ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1271ae349f5Scvs2svn 
1281ae349f5Scvs2svn static const char *cftypes128[] = {
1291ae349f5Scvs2svn   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1301ae349f5Scvs2svn   "???",
1311ae349f5Scvs2svn   "PRIDNS",	/* 129: Primary DNS Server Address */
1321ae349f5Scvs2svn   "PRINBNS",	/* 130: Primary NBNS Server Address */
1331ae349f5Scvs2svn   "SECDNS",	/* 131: Secondary DNS Server Address */
1341ae349f5Scvs2svn   "SECNBNS",	/* 132: Secondary NBNS Server Address */
1351ae349f5Scvs2svn };
1361ae349f5Scvs2svn 
1371ae349f5Scvs2svn #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
1381ae349f5Scvs2svn 
1391ae349f5Scvs2svn void
1401ae349f5Scvs2svn IpcpAddInOctets(int n)
1411ae349f5Scvs2svn {
14229e275ceSBrian Somers   throughput_addin(&IpcpInfo.throughput, n);
1431ae349f5Scvs2svn }
1441ae349f5Scvs2svn 
1451ae349f5Scvs2svn void
1461ae349f5Scvs2svn IpcpAddOutOctets(int n)
1471ae349f5Scvs2svn {
14829e275ceSBrian Somers   throughput_addout(&IpcpInfo.throughput, n);
1491ae349f5Scvs2svn }
1501ae349f5Scvs2svn 
1511ae349f5Scvs2svn int
1521ae349f5Scvs2svn ReportIpcpStatus(struct cmdargs const *arg)
1531ae349f5Scvs2svn {
1541ae349f5Scvs2svn   if (!VarTerm)
1551ae349f5Scvs2svn     return 1;
1567308ec68SBrian Somers   fprintf(VarTerm, "%s [%s]\n", IpcpInfo.fsm.name,
1577308ec68SBrian Somers           StateNames[IpcpInfo.fsm.state]);
1587308ec68SBrian Somers   if (IpcpInfo.fsm.state == ST_OPENED) {
15942e91bc7SBrian Somers     fprintf(VarTerm, " His side:               %s, %s\n",
1601ae349f5Scvs2svn 	    inet_ntoa(IpcpInfo.his_ipaddr), vj2asc(IpcpInfo.his_compproto));
16142e91bc7SBrian Somers     fprintf(VarTerm, " My side:                %s, %s\n",
1621ae349f5Scvs2svn 	    inet_ntoa(IpcpInfo.want_ipaddr), vj2asc(IpcpInfo.want_compproto));
1631ae349f5Scvs2svn   }
1641ae349f5Scvs2svn 
16542e91bc7SBrian Somers   fprintf(VarTerm, "\nDefaults:\n");
1661ae349f5Scvs2svn   fprintf(VarTerm, " My Address:             %s/%d\n",
16729e275ceSBrian Somers 	  inet_ntoa(IpcpInfo.DefMyAddress.ipaddr), IpcpInfo.DefMyAddress.width);
16829e275ceSBrian Somers   if (iplist_isvalid(&IpcpInfo.DefHisChoice))
16942e91bc7SBrian Somers     fprintf(VarTerm, " His Address:            %s\n",
17042e91bc7SBrian Somers             IpcpInfo.DefHisChoice.src);
1711ae349f5Scvs2svn   else
1721ae349f5Scvs2svn     fprintf(VarTerm, " His Address:            %s/%d\n",
17329e275ceSBrian Somers 	  inet_ntoa(IpcpInfo.DefHisAddress.ipaddr),
17429e275ceSBrian Somers           IpcpInfo.DefHisAddress.width);
17529e275ceSBrian Somers   if (IpcpInfo.HaveTriggerAddress)
17629e275ceSBrian Somers     fprintf(VarTerm, " Negotiation(trigger):   %s\n",
17729e275ceSBrian Somers             inet_ntoa(IpcpInfo.TriggerAddress));
1781ae349f5Scvs2svn   else
1791ae349f5Scvs2svn     fprintf(VarTerm, " Negotiation(trigger):   MYADDR\n");
18042e91bc7SBrian Somers   fprintf(VarTerm, " Initial VJ slots:       %d\n", IpcpInfo.VJInitSlots);
18142e91bc7SBrian Somers   fprintf(VarTerm, " Initial VJ compression: %s\n",
18242e91bc7SBrian Somers           IpcpInfo.VJInitComp ? "on" : "off");
1831ae349f5Scvs2svn 
1841ae349f5Scvs2svn   fprintf(VarTerm, "\n");
18529e275ceSBrian Somers   throughput_disp(&IpcpInfo.throughput, VarTerm);
1861ae349f5Scvs2svn 
1871ae349f5Scvs2svn   return 0;
1881ae349f5Scvs2svn }
1891ae349f5Scvs2svn 
1901ae349f5Scvs2svn void
1911ae349f5Scvs2svn IpcpDefAddress()
1921ae349f5Scvs2svn {
1937308ec68SBrian Somers   /* Setup default IP addresses (`hostname` -> 0.0.0.0) */
1941ae349f5Scvs2svn   struct hostent *hp;
1951ae349f5Scvs2svn   char name[200];
1961ae349f5Scvs2svn 
19729e275ceSBrian Somers   memset(&IpcpInfo.DefMyAddress, '\0', sizeof IpcpInfo.DefMyAddress);
19829e275ceSBrian Somers   memset(&IpcpInfo.DefHisAddress, '\0', sizeof IpcpInfo.DefHisAddress);
19929e275ceSBrian Somers   IpcpInfo.HaveTriggerAddress = 0;
2001ae349f5Scvs2svn   if (gethostname(name, sizeof name) == 0) {
2011ae349f5Scvs2svn     hp = gethostbyname(name);
20229e275ceSBrian Somers     if (hp && hp->h_addrtype == AF_INET)
20329e275ceSBrian Somers       memcpy(&IpcpInfo.DefMyAddress.ipaddr.s_addr, hp->h_addr, hp->h_length);
2041ae349f5Scvs2svn   }
2051ae349f5Scvs2svn }
2061ae349f5Scvs2svn 
2071ae349f5Scvs2svn int
2081ae349f5Scvs2svn SetInitVJ(struct cmdargs const *args)
2091ae349f5Scvs2svn {
2101ae349f5Scvs2svn   if (args->argc != 2)
2111ae349f5Scvs2svn     return -1;
2121ae349f5Scvs2svn   if (!strcasecmp(args->argv[0], "slots")) {
2131ae349f5Scvs2svn     int slots;
2141ae349f5Scvs2svn 
2151ae349f5Scvs2svn     slots = atoi(args->argv[1]);
2161ae349f5Scvs2svn     if (slots < 4 || slots > 16)
2171ae349f5Scvs2svn       return 1;
21829e275ceSBrian Somers     IpcpInfo.VJInitSlots = slots;
2191ae349f5Scvs2svn     return 0;
2201ae349f5Scvs2svn   } else if (!strcasecmp(args->argv[0], "slotcomp")) {
2211ae349f5Scvs2svn     if (!strcasecmp(args->argv[1], "on"))
22229e275ceSBrian Somers       IpcpInfo.VJInitComp = 1;
2231ae349f5Scvs2svn     else if (!strcasecmp(args->argv[1], "off"))
22429e275ceSBrian Somers       IpcpInfo.VJInitComp = 0;
2251ae349f5Scvs2svn     else
2261ae349f5Scvs2svn       return 2;
2271ae349f5Scvs2svn     return 0;
2281ae349f5Scvs2svn   }
2291ae349f5Scvs2svn   return -1;
2301ae349f5Scvs2svn }
2311ae349f5Scvs2svn 
2321ae349f5Scvs2svn void
2337a6f8720SBrian Somers IpcpInit(struct bundle *bundle, struct link *l)
2341ae349f5Scvs2svn {
2357308ec68SBrian Somers   /* Initialise ourselves */
2367a6f8720SBrian Somers   FsmInit(&IpcpInfo.fsm, bundle, l);
23729e275ceSBrian Somers   if (iplist_isvalid(&IpcpInfo.DefHisChoice))
23829e275ceSBrian Somers     iplist_setrandpos(&IpcpInfo.DefHisChoice);
23929e275ceSBrian Somers   IpcpInfo.his_compproto = 0;
24029e275ceSBrian Somers   IpcpInfo.his_reject = IpcpInfo.my_reject = 0;
24129e275ceSBrian Somers 
2421ae349f5Scvs2svn   if ((mode & MODE_DEDICATED) && !GetLabel()) {
24329e275ceSBrian Somers     IpcpInfo.want_ipaddr.s_addr = IpcpInfo.his_ipaddr.s_addr = INADDR_ANY;
24429e275ceSBrian Somers     IpcpInfo.his_ipaddr.s_addr = INADDR_ANY;
2451ae349f5Scvs2svn   } else {
24629e275ceSBrian Somers     IpcpInfo.want_ipaddr.s_addr = IpcpInfo.DefMyAddress.ipaddr.s_addr;
24729e275ceSBrian Somers     IpcpInfo.his_ipaddr.s_addr = IpcpInfo.DefHisAddress.ipaddr.s_addr;
2481ae349f5Scvs2svn   }
2491ae349f5Scvs2svn 
2501ae349f5Scvs2svn   /*
2511ae349f5Scvs2svn    * Some implementations of PPP require that we send a
2521ae349f5Scvs2svn    * *special* value as our address, even though the rfc specifies
2531ae349f5Scvs2svn    * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
2541ae349f5Scvs2svn    */
25529e275ceSBrian Somers   if (IpcpInfo.HaveTriggerAddress) {
25629e275ceSBrian Somers     IpcpInfo.want_ipaddr.s_addr = IpcpInfo.TriggerAddress.s_addr;
25729e275ceSBrian Somers     LogPrintf(LogIPCP, "Using trigger address %s\n",
25829e275ceSBrian Somers               inet_ntoa(IpcpInfo.TriggerAddress));
2591ae349f5Scvs2svn   }
260455aabc3SBrian Somers   IpcpInfo.if_mine.s_addr = IpcpInfo.if_peer.s_addr = INADDR_ANY;
26129e275ceSBrian Somers 
2621ae349f5Scvs2svn   if (Enabled(ConfVjcomp))
26329e275ceSBrian Somers     IpcpInfo.want_compproto = (PROTO_VJCOMP << 16) +
26429e275ceSBrian Somers                               ((IpcpInfo.VJInitSlots - 1) << 8) +
26529e275ceSBrian Somers                               IpcpInfo.VJInitComp;
2661ae349f5Scvs2svn   else
2671ae349f5Scvs2svn     IpcpInfo.want_compproto = 0;
2686140ba11SBrian Somers   VjInit(IpcpInfo.VJInitSlots - 1);
26929e275ceSBrian Somers 
2701ae349f5Scvs2svn   IpcpInfo.heis1172 = 0;
2717308ec68SBrian Somers   IpcpInfo.fsm.maxconfig = 10;
27229e275ceSBrian Somers   throughput_init(&IpcpInfo.throughput);
2731ae349f5Scvs2svn }
2741ae349f5Scvs2svn 
275455aabc3SBrian Somers static int
276455aabc3SBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct ipcpstate *ipcp,
277455aabc3SBrian Somers                   struct in_addr myaddr, struct in_addr hisaddr,
278455aabc3SBrian Somers                   struct in_addr netmask, int silent)
279455aabc3SBrian Somers {
280455aabc3SBrian Somers   struct sockaddr_in *sock_in;
281455aabc3SBrian Somers   int s;
282455aabc3SBrian Somers   u_long mask, addr;
283455aabc3SBrian Somers   struct ifaliasreq ifra;
284455aabc3SBrian Somers 
285455aabc3SBrian Somers   /* If given addresses are alreay set, then ignore this request */
286455aabc3SBrian Somers   if (ipcp->if_mine.s_addr == myaddr.s_addr &&
287455aabc3SBrian Somers       ipcp->if_peer.s_addr == hisaddr.s_addr)
288455aabc3SBrian Somers     return 0;
289455aabc3SBrian Somers 
290455aabc3SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
291455aabc3SBrian Somers   if (s < 0) {
292455aabc3SBrian Somers     LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
293455aabc3SBrian Somers     return (-1);
294455aabc3SBrian Somers   }
295455aabc3SBrian Somers 
296455aabc3SBrian Somers   memset(&ifra, '\0', sizeof ifra);
297455aabc3SBrian Somers   strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1);
298455aabc3SBrian Somers   ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
299455aabc3SBrian Somers 
300455aabc3SBrian Somers   /* If different address has been set, then delete it first */
301455aabc3SBrian Somers   if (ipcp->if_mine.s_addr != INADDR_ANY ||
302455aabc3SBrian Somers       ipcp->if_peer.s_addr != INADDR_ANY)
303455aabc3SBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
304455aabc3SBrian Somers       LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCDIFADDR): %s\n",
305455aabc3SBrian Somers 		strerror(errno));
306455aabc3SBrian Somers       close(s);
307455aabc3SBrian Somers       return (-1);
308455aabc3SBrian Somers     }
309455aabc3SBrian Somers 
310455aabc3SBrian Somers   /* Set interface address */
311455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
312455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
313455aabc3SBrian Somers   sock_in->sin_addr = myaddr;
314455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
315455aabc3SBrian Somers 
316455aabc3SBrian Somers   /* Set destination address */
317455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
318455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
319455aabc3SBrian Somers   sock_in->sin_addr = hisaddr;
320455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
321455aabc3SBrian Somers 
322455aabc3SBrian Somers   addr = ntohl(myaddr.s_addr);
323455aabc3SBrian Somers   if (IN_CLASSA(addr))
324455aabc3SBrian Somers     mask = IN_CLASSA_NET;
325455aabc3SBrian Somers   else if (IN_CLASSB(addr))
326455aabc3SBrian Somers     mask = IN_CLASSB_NET;
327455aabc3SBrian Somers   else
328455aabc3SBrian Somers     mask = IN_CLASSC_NET;
329455aabc3SBrian Somers 
330455aabc3SBrian Somers   /* if subnet mask is given, use it instead of class mask */
331455aabc3SBrian Somers   if (netmask.s_addr != INADDR_ANY && (ntohl(netmask.s_addr) & mask) == mask)
332455aabc3SBrian Somers     mask = ntohl(netmask.s_addr);
333455aabc3SBrian Somers 
334455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
335455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
336455aabc3SBrian Somers   sock_in->sin_addr.s_addr = htonl(mask);
337455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
338455aabc3SBrian Somers 
339455aabc3SBrian Somers   if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
340455aabc3SBrian Somers     if (!silent)
341455aabc3SBrian Somers       LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n",
342455aabc3SBrian Somers 		strerror(errno));
343455aabc3SBrian Somers     close(s);
344455aabc3SBrian Somers     return (-1);
345455aabc3SBrian Somers   }
346455aabc3SBrian Somers 
347455aabc3SBrian Somers   ipcp->if_peer.s_addr = hisaddr.s_addr;
348455aabc3SBrian Somers   ipcp->if_mine.s_addr = myaddr.s_addr;
349455aabc3SBrian Somers 
350455aabc3SBrian Somers   if (Enabled(ConfProxy))
351455aabc3SBrian Somers     sifproxyarp(bundle, ipcp, s);
352455aabc3SBrian Somers 
353455aabc3SBrian Somers   close(s);
354455aabc3SBrian Somers   return (0);
355455aabc3SBrian Somers }
356455aabc3SBrian Somers 
357455aabc3SBrian Somers static struct in_addr
358455aabc3SBrian Somers ChooseHisAddr(struct bundle *bundle, struct ipcpstate *ipcp,
359455aabc3SBrian Somers               const struct in_addr gw)
360455aabc3SBrian Somers {
361455aabc3SBrian Somers   struct in_addr try;
362455aabc3SBrian Somers   int f;
363455aabc3SBrian Somers 
364455aabc3SBrian Somers   for (f = 0; f < IpcpInfo.DefHisChoice.nItems; f++) {
365455aabc3SBrian Somers     try = iplist_next(&IpcpInfo.DefHisChoice);
366455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
367455aabc3SBrian Somers               f, inet_ntoa(try));
368455aabc3SBrian Somers     if (ipcp_SetIPaddress(bundle, ipcp, gw, try, ifnetmask, 1) == 0) {
369455aabc3SBrian Somers       LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
370455aabc3SBrian Somers                 inet_ntoa(try));
371455aabc3SBrian Somers       break;
372455aabc3SBrian Somers     }
373455aabc3SBrian Somers   }
374455aabc3SBrian Somers 
375455aabc3SBrian Somers   if (f == IpcpInfo.DefHisChoice.nItems) {
376455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
377455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
378455aabc3SBrian Somers   }
379455aabc3SBrian Somers 
380455aabc3SBrian Somers   return try;
381455aabc3SBrian Somers }
382455aabc3SBrian Somers 
3831ae349f5Scvs2svn static void
3841ae349f5Scvs2svn IpcpInitRestartCounter(struct fsm * fp)
3851ae349f5Scvs2svn {
3867308ec68SBrian Somers   /* Set fsm timer load */
3871ae349f5Scvs2svn   fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
3881ae349f5Scvs2svn   fp->restart = 5;
3891ae349f5Scvs2svn }
3901ae349f5Scvs2svn 
3911ae349f5Scvs2svn static void
3921ae349f5Scvs2svn IpcpSendConfigReq(struct fsm *fp)
3931ae349f5Scvs2svn {
3947308ec68SBrian Somers   /* Send config REQ please */
3958c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
39683d1af55SBrian Somers   struct ipcpstate *ipcp = fsm2ipcp(fp);
3971ae349f5Scvs2svn   u_char *cp;
3981ae349f5Scvs2svn   struct lcp_opt o;
3991ae349f5Scvs2svn 
4001ae349f5Scvs2svn   cp = ReqBuff;
4011ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpSendConfigReq\n");
40283d1af55SBrian Somers   if ((p && !Physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
4031ae349f5Scvs2svn     o.id = TY_IPADDR;
4041ae349f5Scvs2svn     o.len = 6;
40583d1af55SBrian Somers     *(u_long *)o.data = ipcp->want_ipaddr.s_addr;
4061ae349f5Scvs2svn     cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id],
40783d1af55SBrian Somers                      inet_ntoa(ipcp->want_ipaddr));
4081ae349f5Scvs2svn   }
4091ae349f5Scvs2svn 
41083d1af55SBrian Somers   if (ipcp->want_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
4111ae349f5Scvs2svn     const char *args;
4121ae349f5Scvs2svn     o.id = TY_COMPPROTO;
41383d1af55SBrian Somers     if (ipcp->heis1172) {
4141ae349f5Scvs2svn       o.len = 4;
4151ae349f5Scvs2svn       *(u_short *)o.data = htons(PROTO_VJCOMP);
4161ae349f5Scvs2svn       args = "";
4171ae349f5Scvs2svn     } else {
4181ae349f5Scvs2svn       o.len = 6;
41983d1af55SBrian Somers       *(u_long *)o.data = htonl(ipcp->want_compproto);
42083d1af55SBrian Somers       args = vj2asc(ipcp->want_compproto);
4211ae349f5Scvs2svn     }
4221ae349f5Scvs2svn     cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], args);
4231ae349f5Scvs2svn   }
4241ae349f5Scvs2svn   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
4251ae349f5Scvs2svn }
4261ae349f5Scvs2svn 
4271ae349f5Scvs2svn static void
4281ae349f5Scvs2svn IpcpSendTerminateReq(struct fsm * fp)
4291ae349f5Scvs2svn {
4307308ec68SBrian Somers   /* Term REQ just sent by FSM */
4311ae349f5Scvs2svn }
4321ae349f5Scvs2svn 
4331ae349f5Scvs2svn static void
4341ae349f5Scvs2svn IpcpSendTerminateAck(struct fsm * fp)
4351ae349f5Scvs2svn {
4367308ec68SBrian Somers   /* Send Term ACK please */
4371ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpSendTerminateAck\n");
4381ae349f5Scvs2svn   FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
4391ae349f5Scvs2svn }
4401ae349f5Scvs2svn 
4411ae349f5Scvs2svn static void
4421ae349f5Scvs2svn IpcpLayerStart(struct fsm * fp)
4431ae349f5Scvs2svn {
4447308ec68SBrian Somers   /* We're about to start up ! */
4451ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerStart.\n");
446455aabc3SBrian Somers 
447455aabc3SBrian Somers   /* This is where we should be setting up the interface in AUTO mode */
4481ae349f5Scvs2svn }
4491ae349f5Scvs2svn 
4501ae349f5Scvs2svn static void
4511ae349f5Scvs2svn IpcpLayerFinish(struct fsm *fp)
4521ae349f5Scvs2svn {
4537308ec68SBrian Somers   /* We're now down */
4541ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerFinish.\n");
4551ae349f5Scvs2svn }
4561ae349f5Scvs2svn 
4571ae349f5Scvs2svn static void
4581ae349f5Scvs2svn IpcpLayerDown(struct fsm *fp)
4591ae349f5Scvs2svn {
4607308ec68SBrian Somers   /* About to come down */
46183d1af55SBrian Somers   struct ipcpstate *ipcp = fsm2ipcp(fp);
462455aabc3SBrian Somers   const char *s;
463455aabc3SBrian Somers 
464455aabc3SBrian Somers   s = inet_ntoa(ipcp->if_peer);
465455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerDown: %s\n", s);
466455aabc3SBrian Somers 
46783d1af55SBrian Somers   throughput_stop(&ipcp->throughput);
46883d1af55SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
469455aabc3SBrian Somers 
470455aabc3SBrian Somers   /*
471455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
472455aabc3SBrian Somers    * associate executable sections in files with events.
473455aabc3SBrian Somers    */
474455aabc3SBrian Somers   if (SelectSystem(fp->bundle, s, LINKDOWNFILE) < 0)
475455aabc3SBrian Somers     if (GetLabel()) {
476455aabc3SBrian Somers        if (SelectSystem(fp->bundle, GetLabel(), LINKDOWNFILE) < 0)
477455aabc3SBrian Somers        SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE);
478455aabc3SBrian Somers     } else
479455aabc3SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE);
480455aabc3SBrian Somers 
481455aabc3SBrian Somers   if (!(mode & MODE_AUTO)) {
482455aabc3SBrian Somers     struct ifaliasreq ifra;
483455aabc3SBrian Somers     int s;
484455aabc3SBrian Somers 
485455aabc3SBrian Somers     s = ID0socket(AF_INET, SOCK_DGRAM, 0);
486455aabc3SBrian Somers     if (s < 0) {
487455aabc3SBrian Somers       LogPrintf(LogERROR, "IpcpLayerDown: socket: %s\n", strerror(errno));
488455aabc3SBrian Somers       return;
489455aabc3SBrian Somers     }
490455aabc3SBrian Somers 
491455aabc3SBrian Somers     if (Enabled(ConfProxy))
492455aabc3SBrian Somers       cifproxyarp(fp->bundle, ipcp, s);
493455aabc3SBrian Somers 
494455aabc3SBrian Somers     if (ipcp->if_mine.s_addr != INADDR_ANY ||
495455aabc3SBrian Somers         ipcp->if_peer.s_addr != INADDR_ANY) {
496455aabc3SBrian Somers       memset(&ifra, '\0', sizeof ifra);
497455aabc3SBrian Somers       strncpy(ifra.ifra_name, fp->bundle->ifname, sizeof ifra.ifra_name - 1);
498455aabc3SBrian Somers       ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
499455aabc3SBrian Somers       /* XXX don't delete things belonging to other NCPs */
500455aabc3SBrian Somers       if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
501455aabc3SBrian Somers         LogPrintf(LogERROR, "IpcpLayerDown: ioctl(SIOCDIFADDR): %s\n",
502455aabc3SBrian Somers 		  strerror(errno));
503455aabc3SBrian Somers         close(s);
504455aabc3SBrian Somers         return;
505455aabc3SBrian Somers       }
506455aabc3SBrian Somers       ipcp->if_mine.s_addr = ipcp->if_peer.s_addr = INADDR_ANY;
507455aabc3SBrian Somers     }
508455aabc3SBrian Somers 
509455aabc3SBrian Somers     close(s);
510455aabc3SBrian Somers     return;
511455aabc3SBrian Somers   }
5121ae349f5Scvs2svn }
5131ae349f5Scvs2svn 
5141ae349f5Scvs2svn static void
5151ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp)
5161ae349f5Scvs2svn {
5177308ec68SBrian Somers   /* We're now up */
51883d1af55SBrian Somers   struct ipcpstate *ipcp = fsm2ipcp(fp);
5191ae349f5Scvs2svn   char tbuff[100];
5201ae349f5Scvs2svn 
5211ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state);
52283d1af55SBrian Somers   snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->want_ipaddr));
523455aabc3SBrian Somers   LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n",
524455aabc3SBrian Somers 	    tbuff, inet_ntoa(ipcp->his_ipaddr));
5251ae349f5Scvs2svn 
52683d1af55SBrian Somers   if (ipcp->his_compproto >> 16 == PROTO_VJCOMP)
52783d1af55SBrian Somers     VjInit((ipcp->his_compproto >> 8) & 255);
5281ae349f5Scvs2svn 
529455aabc3SBrian Somers   if (ipcp_SetIPaddress(fp->bundle, ipcp, ipcp->want_ipaddr,
530455aabc3SBrian Somers                         ipcp->his_ipaddr, ifnetmask, 0) < 0) {
5311ae349f5Scvs2svn     if (VarTerm)
5321ae349f5Scvs2svn       LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
5331ae349f5Scvs2svn     return;
5341ae349f5Scvs2svn   }
535455aabc3SBrian Somers 
5361ae349f5Scvs2svn #ifndef NOALIAS
5371ae349f5Scvs2svn   if (mode & MODE_ALIAS)
53883d1af55SBrian Somers     VarPacketAliasSetAddress(ipcp->want_ipaddr);
5391ae349f5Scvs2svn #endif
540455aabc3SBrian Somers 
541455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerUp: %s\n",
542455aabc3SBrian Somers             inet_ntoa(ipcp->if_peer));
543455aabc3SBrian Somers 
544455aabc3SBrian Somers   /*
545455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
546455aabc3SBrian Somers    * associate executable sections in files with events.
547455aabc3SBrian Somers    */
548455aabc3SBrian Somers   if (SelectSystem(fp->bundle, inet_ntoa(ipcp->if_mine), LINKUPFILE) < 0)
549455aabc3SBrian Somers     if (GetLabel()) {
550455aabc3SBrian Somers       if (SelectSystem(fp->bundle, GetLabel(), LINKUPFILE) < 0)
551455aabc3SBrian Somers         SelectSystem(fp->bundle, "MYADDR", LINKUPFILE);
552455aabc3SBrian Somers     } else
553455aabc3SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKUPFILE);
554455aabc3SBrian Somers 
55583d1af55SBrian Somers   throughput_start(&ipcp->throughput);
5561ae349f5Scvs2svn   StartIdleTimer();
557455aabc3SBrian Somers   Prompt(fp->bundle);
5581ae349f5Scvs2svn }
5591ae349f5Scvs2svn 
5601ae349f5Scvs2svn void
5611ae349f5Scvs2svn IpcpUp()
5621ae349f5Scvs2svn {
5637308ec68SBrian Somers   /* Lower layers are ready.... go */
5647308ec68SBrian Somers   FsmUp(&IpcpInfo.fsm);
5651ae349f5Scvs2svn   LogPrintf(LogIPCP, "IPCP Up event!!\n");
5661ae349f5Scvs2svn }
5671ae349f5Scvs2svn 
5681ae349f5Scvs2svn void
5691ae349f5Scvs2svn IpcpOpen()
5701ae349f5Scvs2svn {
5717308ec68SBrian Somers   /* Start IPCP please */
5727308ec68SBrian Somers   FsmOpen(&IpcpInfo.fsm);
5731ae349f5Scvs2svn }
5741ae349f5Scvs2svn 
5751ae349f5Scvs2svn static int
5761ae349f5Scvs2svn AcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
5771ae349f5Scvs2svn {
5787308ec68SBrian Somers   /* Is the given IP in the given range ? */
5791ae349f5Scvs2svn   LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr));
5801ae349f5Scvs2svn   LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr));
5811ae349f5Scvs2svn   LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr));
5821ae349f5Scvs2svn   LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange->
5831ae349f5Scvs2svn 		  mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr));
5841ae349f5Scvs2svn   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
5851ae349f5Scvs2svn     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
5861ae349f5Scvs2svn }
5871ae349f5Scvs2svn 
5881ae349f5Scvs2svn static void
58983d1af55SBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type)
5901ae349f5Scvs2svn {
5917308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
59283d1af55SBrian Somers   struct ipcpstate *ipcp = fsm2ipcp(fp);
5931ae349f5Scvs2svn   int type, length;
5941ae349f5Scvs2svn   u_long *lp, compproto;
5951ae349f5Scvs2svn   struct compreq *pcomp;
5961ae349f5Scvs2svn   struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
5971ae349f5Scvs2svn   char tbuff[100];
5981ae349f5Scvs2svn   char tbuff2[100];
5991ae349f5Scvs2svn 
6001ae349f5Scvs2svn   ackp = AckBuff;
6011ae349f5Scvs2svn   nakp = NakBuff;
6021ae349f5Scvs2svn   rejp = RejBuff;
6031ae349f5Scvs2svn 
6041ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
6051ae349f5Scvs2svn     type = *cp;
6061ae349f5Scvs2svn     length = cp[1];
6071ae349f5Scvs2svn     if (type < NCFTYPES)
6081ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
6091ae349f5Scvs2svn     else if (type > 128 && type < 128 + NCFTYPES128)
6101ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
6111ae349f5Scvs2svn     else
6121ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
6131ae349f5Scvs2svn 
6141ae349f5Scvs2svn     switch (type) {
6151ae349f5Scvs2svn     case TY_IPADDR:		/* RFC1332 */
6161ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6171ae349f5Scvs2svn       ipaddr.s_addr = *lp;
6181ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
6191ae349f5Scvs2svn 
6201ae349f5Scvs2svn       switch (mode_type) {
6211ae349f5Scvs2svn       case MODE_REQ:
62283d1af55SBrian Somers         if (iplist_isvalid(&ipcp->DefHisChoice)) {
6231ae349f5Scvs2svn           if (ipaddr.s_addr == INADDR_ANY ||
62483d1af55SBrian Somers               iplist_ip2pos(&ipcp->DefHisChoice, ipaddr) < 0 ||
625455aabc3SBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp, ipcp->DefMyAddress.ipaddr,
626455aabc3SBrian Somers                                 ipaddr, ifnetmask, 1)) {
6271ae349f5Scvs2svn             LogPrintf(LogIPCP, "%s: Address invalid or already in use\n",
6281ae349f5Scvs2svn                       inet_ntoa(ipaddr));
62983d1af55SBrian Somers             ipcp->his_ipaddr = ChooseHisAddr
630455aabc3SBrian Somers               (fp->bundle, ipcp, ipcp->DefMyAddress.ipaddr);
63183d1af55SBrian Somers             if (ipcp->his_ipaddr.s_addr == INADDR_ANY) {
6321ae349f5Scvs2svn 	      memcpy(rejp, cp, length);
6331ae349f5Scvs2svn 	      rejp += length;
6341ae349f5Scvs2svn             } else {
6351ae349f5Scvs2svn 	      memcpy(nakp, cp, 2);
63683d1af55SBrian Somers 	      memcpy(nakp+2, &ipcp->his_ipaddr.s_addr, length - 2);
6371ae349f5Scvs2svn 	      nakp += length;
6381ae349f5Scvs2svn             }
6391ae349f5Scvs2svn 	    break;
6401ae349f5Scvs2svn           }
64183d1af55SBrian Somers 	} else if (!AcceptableAddr(&ipcp->DefHisAddress, ipaddr)) {
6421ae349f5Scvs2svn 	  /*
6431ae349f5Scvs2svn 	   * If destination address is not acceptable, insist to use what we
6441ae349f5Scvs2svn 	   * want to use.
6451ae349f5Scvs2svn 	   */
6461ae349f5Scvs2svn 	  memcpy(nakp, cp, 2);
64783d1af55SBrian Somers 	  memcpy(nakp+2, &ipcp->his_ipaddr.s_addr, length - 2);
6481ae349f5Scvs2svn 	  nakp += length;
6491ae349f5Scvs2svn 	  break;
6501ae349f5Scvs2svn 	}
65183d1af55SBrian Somers 	ipcp->his_ipaddr = ipaddr;
6521ae349f5Scvs2svn 	memcpy(ackp, cp, length);
6531ae349f5Scvs2svn 	ackp += length;
6541ae349f5Scvs2svn 	break;
6551ae349f5Scvs2svn       case MODE_NAK:
65683d1af55SBrian Somers 	if (AcceptableAddr(&ipcp->DefMyAddress, ipaddr)) {
6571ae349f5Scvs2svn 	  /* Use address suggested by peer */
6581ae349f5Scvs2svn 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
65983d1af55SBrian Somers 		   inet_ntoa(ipcp->want_ipaddr));
6601ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
66183d1af55SBrian Somers 	  ipcp->want_ipaddr = ipaddr;
6621ae349f5Scvs2svn 	} else {
6631ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
66483d1af55SBrian Somers           FsmClose(&ipcp->fsm);
6651ae349f5Scvs2svn 	}
6661ae349f5Scvs2svn 	break;
6671ae349f5Scvs2svn       case MODE_REJ:
66883d1af55SBrian Somers 	ipcp->his_reject |= (1 << type);
6691ae349f5Scvs2svn 	break;
6701ae349f5Scvs2svn       }
6711ae349f5Scvs2svn       break;
6721ae349f5Scvs2svn     case TY_COMPPROTO:
6731ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6741ae349f5Scvs2svn       compproto = htonl(*lp);
6751ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
6761ae349f5Scvs2svn 
6771ae349f5Scvs2svn       switch (mode_type) {
6781ae349f5Scvs2svn       case MODE_REQ:
6791ae349f5Scvs2svn 	if (!Acceptable(ConfVjcomp)) {
6801ae349f5Scvs2svn 	  memcpy(rejp, cp, length);
6811ae349f5Scvs2svn 	  rejp += length;
6821ae349f5Scvs2svn 	} else {
6831ae349f5Scvs2svn 	  pcomp = (struct compreq *) (cp + 2);
6841ae349f5Scvs2svn 	  switch (length) {
6851ae349f5Scvs2svn 	  case 4:		/* RFC1172 */
6861ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
6871ae349f5Scvs2svn 	      LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
68883d1af55SBrian Somers 	      ipcp->heis1172 = 1;
68983d1af55SBrian Somers 	      ipcp->his_compproto = compproto;
6901ae349f5Scvs2svn 	      memcpy(ackp, cp, length);
6911ae349f5Scvs2svn 	      ackp += length;
6921ae349f5Scvs2svn 	    } else {
6931ae349f5Scvs2svn 	      memcpy(nakp, cp, 2);
6941ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
6951ae349f5Scvs2svn 	      memcpy(nakp+2, &pcomp, 2);
6961ae349f5Scvs2svn 	      nakp += length;
6971ae349f5Scvs2svn 	    }
6981ae349f5Scvs2svn 	    break;
6991ae349f5Scvs2svn 	  case 6:		/* RFC1332 */
7001ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
70129e275ceSBrian Somers 		&& pcomp->slots < MAX_VJ_STATES && pcomp->slots > 2) {
70283d1af55SBrian Somers 	      ipcp->his_compproto = compproto;
70383d1af55SBrian Somers 	      ipcp->heis1172 = 0;
7041ae349f5Scvs2svn 	      memcpy(ackp, cp, length);
7051ae349f5Scvs2svn 	      ackp += length;
7061ae349f5Scvs2svn 	    } else {
7071ae349f5Scvs2svn 	      memcpy(nakp, cp, 2);
7081ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
70929e275ceSBrian Somers 	      pcomp->slots = MAX_VJ_STATES - 1;
7101ae349f5Scvs2svn 	      pcomp->compcid = 0;
7111ae349f5Scvs2svn 	      memcpy(nakp+2, &pcomp, sizeof pcomp);
7121ae349f5Scvs2svn 	      nakp += length;
7131ae349f5Scvs2svn 	    }
7141ae349f5Scvs2svn 	    break;
7151ae349f5Scvs2svn 	  default:
7161ae349f5Scvs2svn 	    memcpy(rejp, cp, length);
7171ae349f5Scvs2svn 	    rejp += length;
7181ae349f5Scvs2svn 	    break;
7191ae349f5Scvs2svn 	  }
7201ae349f5Scvs2svn 	}
7211ae349f5Scvs2svn 	break;
7221ae349f5Scvs2svn       case MODE_NAK:
7231ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
72483d1af55SBrian Somers 		  tbuff, ipcp->want_compproto, compproto);
72583d1af55SBrian Somers 	ipcp->want_compproto = compproto;
7261ae349f5Scvs2svn 	break;
7271ae349f5Scvs2svn       case MODE_REJ:
72883d1af55SBrian Somers 	ipcp->his_reject |= (1 << type);
7291ae349f5Scvs2svn 	break;
7301ae349f5Scvs2svn       }
7311ae349f5Scvs2svn       break;
7321ae349f5Scvs2svn     case TY_IPADDRS:		/* RFC1172 */
7331ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
7341ae349f5Scvs2svn       ipaddr.s_addr = *lp;
7351ae349f5Scvs2svn       lp = (u_long *) (cp + 6);
7361ae349f5Scvs2svn       dstipaddr.s_addr = *lp;
7371ae349f5Scvs2svn       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
7381ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
7391ae349f5Scvs2svn 
7401ae349f5Scvs2svn       switch (mode_type) {
7411ae349f5Scvs2svn       case MODE_REQ:
74283d1af55SBrian Somers 	ipcp->his_ipaddr = ipaddr;
74383d1af55SBrian Somers 	ipcp->want_ipaddr = dstipaddr;
7441ae349f5Scvs2svn 	memcpy(ackp, cp, length);
7451ae349f5Scvs2svn 	ackp += length;
7461ae349f5Scvs2svn 	break;
7471ae349f5Scvs2svn       case MODE_NAK:
7481ae349f5Scvs2svn         snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
74983d1af55SBrian Somers 		 inet_ntoa(ipcp->want_ipaddr));
7501ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
75183d1af55SBrian Somers 	ipcp->want_ipaddr = ipaddr;
75283d1af55SBrian Somers 	ipcp->his_ipaddr = dstipaddr;
7531ae349f5Scvs2svn 	break;
7541ae349f5Scvs2svn       case MODE_REJ:
75583d1af55SBrian Somers 	ipcp->his_reject |= (1 << type);
7561ae349f5Scvs2svn 	break;
7571ae349f5Scvs2svn       }
7581ae349f5Scvs2svn       break;
7591ae349f5Scvs2svn 
7601ae349f5Scvs2svn       /*
7611ae349f5Scvs2svn        * MS extensions for MS's PPP
7621ae349f5Scvs2svn        */
7631ae349f5Scvs2svn 
7641ae349f5Scvs2svn #ifndef NOMSEXT
7651ae349f5Scvs2svn     case TY_PRIMARY_DNS:	/* MS PPP DNS negotiation hack */
7661ae349f5Scvs2svn     case TY_SECONDARY_DNS:
7671ae349f5Scvs2svn       if (!Enabled(ConfMSExt)) {
7681ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n");
76983d1af55SBrian Somers 	ipcp->my_reject |= (1 << type);
7701ae349f5Scvs2svn 	memcpy(rejp, cp, length);
7711ae349f5Scvs2svn 	rejp += length;
7721ae349f5Scvs2svn 	break;
7731ae349f5Scvs2svn       }
7741ae349f5Scvs2svn       switch (mode_type) {
7751ae349f5Scvs2svn       case MODE_REQ:
7761ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
7771ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
77883d1af55SBrian Somers 	ms_info_req.s_addr = ipcp->ns_entries
77929e275ceSBrian Somers           [(type - TY_PRIMARY_DNS) ? 1 : 0].s_addr;
7801ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
7811ae349f5Scvs2svn 
7821ae349f5Scvs2svn 	  /*
7831ae349f5Scvs2svn 	   * So the client has got the DNS stuff wrong (first request) so
7841ae349f5Scvs2svn 	   * we'll tell 'em how it is
7851ae349f5Scvs2svn 	   */
7861ae349f5Scvs2svn 	  memcpy(nakp, cp, 2);	/* copy first two (type/length) */
7871ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n",
7881ae349f5Scvs2svn 		    type,
7891ae349f5Scvs2svn 		    inet_ntoa(dnsstuff),
7901ae349f5Scvs2svn 		    inet_ntoa(ms_info_req));
7911ae349f5Scvs2svn 	  memcpy(nakp+2, &ms_info_req, length);
7921ae349f5Scvs2svn 	  nakp += length;
7931ae349f5Scvs2svn 	  break;
7941ae349f5Scvs2svn 	}
7951ae349f5Scvs2svn 
7961ae349f5Scvs2svn 	/*
7971ae349f5Scvs2svn 	 * Otherwise they have it right (this time) so we send a ack packet
7981ae349f5Scvs2svn 	 * back confirming it... end of story
7991ae349f5Scvs2svn 	 */
8001ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n",
8011ae349f5Scvs2svn 		  type,
8021ae349f5Scvs2svn 		  inet_ntoa(ms_info_req));
8031ae349f5Scvs2svn 	memcpy(ackp, cp, length);
8041ae349f5Scvs2svn 	ackp += length;
8051ae349f5Scvs2svn 	break;
8061ae349f5Scvs2svn       case MODE_NAK:		/* what does this mean?? */
8071ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type);
8081ae349f5Scvs2svn 	break;
8091ae349f5Scvs2svn       case MODE_REJ:		/* confused?? me to :) */
8101ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type);
8111ae349f5Scvs2svn 	break;
8121ae349f5Scvs2svn       }
8131ae349f5Scvs2svn       break;
8141ae349f5Scvs2svn 
8151ae349f5Scvs2svn     case TY_PRIMARY_NBNS:	/* MS PPP NetBIOS nameserver hack */
8161ae349f5Scvs2svn     case TY_SECONDARY_NBNS:
8171ae349f5Scvs2svn       if (!Enabled(ConfMSExt)) {
8181ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n");
81983d1af55SBrian Somers 	ipcp->my_reject |= (1 << type);
8201ae349f5Scvs2svn 	memcpy(rejp, cp, length);
8211ae349f5Scvs2svn 	rejp += length;
8221ae349f5Scvs2svn 	break;
8231ae349f5Scvs2svn       }
8241ae349f5Scvs2svn       switch (mode_type) {
8251ae349f5Scvs2svn       case MODE_REQ:
8261ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
8271ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
82883d1af55SBrian Somers 	ms_info_req.s_addr = ipcp->nbns_entries
82929e275ceSBrian Somers           [(type - TY_PRIMARY_NBNS) ? 1 : 0].s_addr;
8301ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
8311ae349f5Scvs2svn 	  memcpy(nakp, cp, 2);
8321ae349f5Scvs2svn 	  memcpy(nakp+2, &ms_info_req.s_addr, length);
8331ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n",
8341ae349f5Scvs2svn 		    type,
8351ae349f5Scvs2svn 		    inet_ntoa(dnsstuff),
8361ae349f5Scvs2svn 		    inet_ntoa(ms_info_req));
8371ae349f5Scvs2svn 	  nakp += length;
8381ae349f5Scvs2svn 	  break;
8391ae349f5Scvs2svn 	}
8401ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n",
8411ae349f5Scvs2svn 		  type,
8421ae349f5Scvs2svn 		  inet_ntoa(ms_info_req));
8431ae349f5Scvs2svn 	memcpy(ackp, cp, length);
8441ae349f5Scvs2svn 	ackp += length;
8451ae349f5Scvs2svn 	break;
8461ae349f5Scvs2svn       case MODE_NAK:
8471ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
8481ae349f5Scvs2svn 	break;
8491ae349f5Scvs2svn       case MODE_REJ:
8501ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
8511ae349f5Scvs2svn 	break;
8521ae349f5Scvs2svn       }
8531ae349f5Scvs2svn       break;
8541ae349f5Scvs2svn 
8551ae349f5Scvs2svn #endif
8561ae349f5Scvs2svn 
8571ae349f5Scvs2svn     default:
85883d1af55SBrian Somers       ipcp->my_reject |= (1 << type);
8591ae349f5Scvs2svn       memcpy(rejp, cp, length);
8601ae349f5Scvs2svn       rejp += length;
8611ae349f5Scvs2svn       break;
8621ae349f5Scvs2svn     }
8631ae349f5Scvs2svn     plen -= length;
8641ae349f5Scvs2svn     cp += length;
8651ae349f5Scvs2svn   }
8661ae349f5Scvs2svn }
8671ae349f5Scvs2svn 
8681ae349f5Scvs2svn void
8691ae349f5Scvs2svn IpcpInput(struct mbuf * bp)
8701ae349f5Scvs2svn {
8717308ec68SBrian Somers   /* Got PROTO_IPCP from link */
8727308ec68SBrian Somers   FsmInput(&IpcpInfo.fsm, bp);
8731ae349f5Scvs2svn }
8741ae349f5Scvs2svn 
8751ae349f5Scvs2svn int
8767a6f8720SBrian Somers UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
8771ae349f5Scvs2svn {
8787308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
87929e275ceSBrian Somers   memset(&IpcpInfo.DefHisAddress, '\0', sizeof IpcpInfo.DefHisAddress);
88029e275ceSBrian Somers   iplist_reset(&IpcpInfo.DefHisChoice);
8811ae349f5Scvs2svn   if (strpbrk(hisaddr, ",-")) {
88229e275ceSBrian Somers     iplist_setsrc(&IpcpInfo.DefHisChoice, hisaddr);
88329e275ceSBrian Somers     if (iplist_isvalid(&IpcpInfo.DefHisChoice)) {
88429e275ceSBrian Somers       iplist_setrandpos(&IpcpInfo.DefHisChoice);
885455aabc3SBrian Somers       IpcpInfo.his_ipaddr = ChooseHisAddr
886455aabc3SBrian Somers         (bundle, &IpcpInfo, IpcpInfo.want_ipaddr);
8871ae349f5Scvs2svn       if (IpcpInfo.his_ipaddr.s_addr == INADDR_ANY) {
88829e275ceSBrian Somers         LogPrintf(LogWARN, "%s: None available !\n", IpcpInfo.DefHisChoice.src);
8891ae349f5Scvs2svn         return(0);
8901ae349f5Scvs2svn       }
89129e275ceSBrian Somers       IpcpInfo.DefHisAddress.ipaddr.s_addr = IpcpInfo.his_ipaddr.s_addr;
89229e275ceSBrian Somers       IpcpInfo.DefHisAddress.mask.s_addr = INADDR_BROADCAST;
89329e275ceSBrian Somers       IpcpInfo.DefHisAddress.width = 32;
8941ae349f5Scvs2svn     } else {
8951ae349f5Scvs2svn       LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr);
8961ae349f5Scvs2svn       return 0;
8971ae349f5Scvs2svn     }
89829e275ceSBrian Somers   } else if (ParseAddr(1, &hisaddr, &IpcpInfo.DefHisAddress.ipaddr,
89929e275ceSBrian Somers 		       &IpcpInfo.DefHisAddress.mask,
90029e275ceSBrian Somers                        &IpcpInfo.DefHisAddress.width) != 0) {
90129e275ceSBrian Somers     IpcpInfo.his_ipaddr.s_addr = IpcpInfo.DefHisAddress.ipaddr.s_addr;
9021ae349f5Scvs2svn 
903455aabc3SBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, &IpcpInfo,
904455aabc3SBrian Somers                                      IpcpInfo.DefMyAddress.ipaddr,
905455aabc3SBrian Somers                                      IpcpInfo.DefHisAddress.ipaddr, ifnetmask,
906455aabc3SBrian Somers                                      0) < 0) {
90729e275ceSBrian Somers       IpcpInfo.DefMyAddress.ipaddr.s_addr = INADDR_ANY;
90829e275ceSBrian Somers       IpcpInfo.DefHisAddress.ipaddr.s_addr = INADDR_ANY;
9091ae349f5Scvs2svn       return 0;
9101ae349f5Scvs2svn     }
9111ae349f5Scvs2svn   } else
9121ae349f5Scvs2svn     return 0;
9131ae349f5Scvs2svn 
9141ae349f5Scvs2svn   return 1;
9151ae349f5Scvs2svn }
916