xref: /freebsd/usr.sbin/ppp/ipcp.c (revision b6217683dc0269a53b799399522dbdfb5a4919cc)
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  *
20b6217683SBrian Somers  * $Id: ipcp.c,v 1.50.2.30 1998/04/03 19:25:04 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 "slcompress.h"
54eaa4df37SBrian Somers #include "ipcp.h"
555ca5389aSBrian Somers #include "filter.h"
562f786681SBrian Somers #include "descriptor.h"
571ae349f5Scvs2svn #include "loadalias.h"
581ae349f5Scvs2svn #include "vars.h"
591ae349f5Scvs2svn #include "vjcomp.h"
601ae349f5Scvs2svn #include "ip.h"
611ae349f5Scvs2svn #include "route.h"
62879ed6faSBrian Somers #include "lqr.h"
638c07a7b2SBrian Somers #include "hdlc.h"
646140ba11SBrian Somers #include "async.h"
653b0f8d2eSBrian Somers #include "ccp.h"
668c07a7b2SBrian Somers #include "link.h"
6763b73463SBrian Somers #include "physical.h"
683b0f8d2eSBrian Somers #include "mp.h"
693b0f8d2eSBrian Somers #include "bundle.h"
70455aabc3SBrian Somers #include "id.h"
71455aabc3SBrian Somers #include "arp.h"
72455aabc3SBrian Somers #include "systems.h"
7385b542cfSBrian Somers #include "prompt.h"
741ae349f5Scvs2svn 
75503a7782SBrian Somers #undef REJECTED
76503a7782SBrian Somers #define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
77503a7782SBrian Somers 
7829e275ceSBrian Somers struct compreq {
7929e275ceSBrian Somers   u_short proto;
8029e275ceSBrian Somers   u_char slots;
8129e275ceSBrian Somers   u_char compcid;
8229e275ceSBrian Somers };
831ae349f5Scvs2svn 
841ae349f5Scvs2svn static void IpcpLayerUp(struct fsm *);
851ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *);
867308ec68SBrian Somers static void IpcpLayerStart(struct fsm *);
877308ec68SBrian Somers static void IpcpLayerFinish(struct fsm *);
881ae349f5Scvs2svn static void IpcpInitRestartCounter(struct fsm *);
897308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *);
902267893fSBrian Somers static void IpcpSentTerminateReq(struct fsm *);
912267893fSBrian Somers static void IpcpSendTerminateAck(struct fsm *, u_char);
9230c2f2ffSBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
9330c2f2ffSBrian Somers                              struct fsm_decode *);
9483d1af55SBrian Somers 
9583d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = {
9683d1af55SBrian Somers   IpcpLayerUp,
9783d1af55SBrian Somers   IpcpLayerDown,
9883d1af55SBrian Somers   IpcpLayerStart,
996d666775SBrian Somers   IpcpLayerFinish,
10083d1af55SBrian Somers   IpcpInitRestartCounter,
10183d1af55SBrian Somers   IpcpSendConfigReq,
1022267893fSBrian Somers   IpcpSentTerminateReq,
10383d1af55SBrian Somers   IpcpSendTerminateAck,
10483d1af55SBrian Somers   IpcpDecodeConfig,
105503a7782SBrian Somers   NullRecvResetReq,
106503a7782SBrian Somers   NullRecvResetAck
10783d1af55SBrian Somers };
1081ae349f5Scvs2svn 
1091ae349f5Scvs2svn static const char *cftypes[] = {
1101ae349f5Scvs2svn   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1111ae349f5Scvs2svn   "???",
1121ae349f5Scvs2svn   "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
1131ae349f5Scvs2svn   "COMPPROTO",	/* 2: IP-Compression-Protocol */
1141ae349f5Scvs2svn   "IPADDR",	/* 3: IP-Address */
1151ae349f5Scvs2svn };
1161ae349f5Scvs2svn 
1171ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1181ae349f5Scvs2svn 
1191ae349f5Scvs2svn static const char *cftypes128[] = {
1201ae349f5Scvs2svn   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1211ae349f5Scvs2svn   "???",
1221ae349f5Scvs2svn   "PRIDNS",	/* 129: Primary DNS Server Address */
1231ae349f5Scvs2svn   "PRINBNS",	/* 130: Primary NBNS Server Address */
1241ae349f5Scvs2svn   "SECDNS",	/* 131: Secondary DNS Server Address */
1251ae349f5Scvs2svn   "SECNBNS",	/* 132: Secondary NBNS Server Address */
1261ae349f5Scvs2svn };
1271ae349f5Scvs2svn 
1281ae349f5Scvs2svn #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
1291ae349f5Scvs2svn 
1301ae349f5Scvs2svn void
1315828db6dSBrian Somers ipcp_AddInOctets(struct ipcp *ipcp, int n)
1321ae349f5Scvs2svn {
1335828db6dSBrian Somers   throughput_addin(&ipcp->throughput, n);
1341ae349f5Scvs2svn }
1351ae349f5Scvs2svn 
1361ae349f5Scvs2svn void
1375828db6dSBrian Somers ipcp_AddOutOctets(struct ipcp *ipcp, int n)
1381ae349f5Scvs2svn {
1395828db6dSBrian Somers   throughput_addout(&ipcp->throughput, n);
1401ae349f5Scvs2svn }
1411ae349f5Scvs2svn 
1421ae349f5Scvs2svn int
1431ae349f5Scvs2svn ReportIpcpStatus(struct cmdargs const *arg)
1441ae349f5Scvs2svn {
145b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s [%s]\n", arg->bundle->ncp.ipcp.fsm.name,
1461e991daaSBrian Somers           State2Nam(arg->bundle->ncp.ipcp.fsm.state));
1475828db6dSBrian Somers   if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) {
148b6217683SBrian Somers     prompt_Printf(arg->prompt, " His side:               %s, %s\n",
1495828db6dSBrian Somers 	    inet_ntoa(arg->bundle->ncp.ipcp.peer_ip),
1505828db6dSBrian Somers             vj2asc(arg->bundle->ncp.ipcp.peer_compproto));
151b6217683SBrian Somers     prompt_Printf(arg->prompt, " My side:                %s, %s\n",
1525828db6dSBrian Somers 	    inet_ntoa(arg->bundle->ncp.ipcp.my_ip),
1535828db6dSBrian Somers             vj2asc(arg->bundle->ncp.ipcp.my_compproto));
1541ae349f5Scvs2svn   }
1551ae349f5Scvs2svn 
156b6217683SBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
157b6217683SBrian Somers   prompt_Printf(arg->prompt, " My Address:             %s/%d\n",
1585828db6dSBrian Somers 	  inet_ntoa(arg->bundle->ncp.ipcp.cfg.my_range.ipaddr),
1595828db6dSBrian Somers           arg->bundle->ncp.ipcp.cfg.my_range.width);
1605828db6dSBrian Somers   if (iplist_isvalid(&arg->bundle->ncp.ipcp.cfg.peer_list))
161b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:            %s\n",
1625828db6dSBrian Somers             arg->bundle->ncp.ipcp.cfg.peer_list.src);
1631ae349f5Scvs2svn   else
164b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:            %s/%d\n",
1655828db6dSBrian Somers 	  inet_ntoa(arg->bundle->ncp.ipcp.cfg.peer_range.ipaddr),
1665828db6dSBrian Somers           arg->bundle->ncp.ipcp.cfg.peer_range.width);
1675828db6dSBrian Somers   if (arg->bundle->ncp.ipcp.cfg.HaveTriggerAddress)
168b6217683SBrian Somers     prompt_Printf(arg->prompt, " Negotiation(trigger):   %s\n",
1695828db6dSBrian Somers             inet_ntoa(arg->bundle->ncp.ipcp.cfg.TriggerAddress));
1701ae349f5Scvs2svn   else
171b6217683SBrian Somers     prompt_Printf(arg->prompt, " Negotiation(trigger):   MYADDR\n");
172b6217683SBrian Somers   prompt_Printf(arg->prompt, " Initial VJ slots:       %d\n",
1735828db6dSBrian Somers                 arg->bundle->ncp.ipcp.cfg.VJInitSlots);
174b6217683SBrian Somers   prompt_Printf(arg->prompt, " Initial VJ compression: %s\n",
1755828db6dSBrian Somers           arg->bundle->ncp.ipcp.cfg.VJInitComp ? "on" : "off");
1761ae349f5Scvs2svn 
177b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n");
178b6217683SBrian Somers   throughput_disp(&arg->bundle->ncp.ipcp.throughput, arg->prompt);
1791ae349f5Scvs2svn 
1801ae349f5Scvs2svn   return 0;
1811ae349f5Scvs2svn }
1821ae349f5Scvs2svn 
1831ae349f5Scvs2svn int
1845828db6dSBrian Somers SetInitVJ(struct cmdargs const *arg)
1851ae349f5Scvs2svn {
1865828db6dSBrian Somers   if (arg->argc != 2)
1871ae349f5Scvs2svn     return -1;
1885828db6dSBrian Somers   if (!strcasecmp(arg->argv[0], "slots")) {
1891ae349f5Scvs2svn     int slots;
1901ae349f5Scvs2svn 
1915828db6dSBrian Somers     slots = atoi(arg->argv[1]);
1921ae349f5Scvs2svn     if (slots < 4 || slots > 16)
1931ae349f5Scvs2svn       return 1;
1945828db6dSBrian Somers     arg->bundle->ncp.ipcp.cfg.VJInitSlots = slots;
1951ae349f5Scvs2svn     return 0;
1965828db6dSBrian Somers   } else if (!strcasecmp(arg->argv[0], "slotcomp")) {
1975828db6dSBrian Somers     if (!strcasecmp(arg->argv[1], "on"))
1985828db6dSBrian Somers       arg->bundle->ncp.ipcp.cfg.VJInitComp = 1;
1995828db6dSBrian Somers     else if (!strcasecmp(arg->argv[1], "off"))
2005828db6dSBrian Somers       arg->bundle->ncp.ipcp.cfg.VJInitComp = 0;
2011ae349f5Scvs2svn     else
2021ae349f5Scvs2svn       return 2;
2031ae349f5Scvs2svn     return 0;
2041ae349f5Scvs2svn   }
2051ae349f5Scvs2svn   return -1;
2061ae349f5Scvs2svn }
2071ae349f5Scvs2svn 
2081ae349f5Scvs2svn void
2096d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
2106d666775SBrian Somers           const struct fsm_parent *parent)
2111ae349f5Scvs2svn {
212503a7782SBrian Somers   struct hostent *hp;
213503a7782SBrian Somers   char name[MAXHOSTNAMELEN];
2143b0f8d2eSBrian Somers   static const char *timer_names[] =
2153b0f8d2eSBrian Somers     {"IPCP restart", "IPCP openmode", "IPCP stopped"};
21629e275ceSBrian Somers 
2173b0f8d2eSBrian Somers   fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP,
2183b0f8d2eSBrian Somers            bundle, l, parent, &ipcp_Callbacks, timer_names);
219503a7782SBrian Somers 
220503a7782SBrian Somers   ipcp->cfg.VJInitSlots = DEF_VJ_STATES;
221503a7782SBrian Somers   ipcp->cfg.VJInitComp = 1;
222503a7782SBrian Somers   memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
223503a7782SBrian Somers   if (gethostname(name, sizeof name) == 0) {
224503a7782SBrian Somers     hp = gethostbyname(name);
225503a7782SBrian Somers     if (hp && hp->h_addrtype == AF_INET) {
226503a7782SBrian Somers       memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
227503a7782SBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
228503a7782SBrian Somers       ipcp->cfg.peer_range.width = 32;
2291ae349f5Scvs2svn     }
230503a7782SBrian Somers   }
23130c2f2ffSBrian Somers   ipcp->cfg.netmask.s_addr = INADDR_ANY;
232503a7782SBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
233503a7782SBrian Somers   iplist_setsrc(&ipcp->cfg.peer_list, "");
234503a7782SBrian Somers   ipcp->cfg.HaveTriggerAddress = 0;
235503a7782SBrian Somers 
236cd9647a1SBrian Somers #ifndef NOMSEXT
237503a7782SBrian Somers   ipcp->cfg.ns_entries[0].s_addr = INADDR_ANY;
238503a7782SBrian Somers   ipcp->cfg.ns_entries[1].s_addr = INADDR_ANY;
239503a7782SBrian Somers   ipcp->cfg.nbns_entries[0].s_addr = INADDR_ANY;
240503a7782SBrian Somers   ipcp->cfg.nbns_entries[1].s_addr = INADDR_ANY;
241cd9647a1SBrian Somers #endif
242cd9647a1SBrian Somers 
243cd9647a1SBrian Somers   ipcp->cfg.fsmretry = DEF_FSMRETRY;
244503a7782SBrian Somers 
245eaa4df37SBrian Somers   memset(&ipcp->vj, '\0', sizeof ipcp->vj);
246eaa4df37SBrian Somers 
247503a7782SBrian Somers   ipcp->my_ifip.s_addr = INADDR_ANY;
248503a7782SBrian Somers   ipcp->peer_ifip.s_addr = INADDR_ANY;
249503a7782SBrian Somers 
250503a7782SBrian Somers   ipcp_Setup(ipcp);
251503a7782SBrian Somers }
252503a7782SBrian Somers 
253503a7782SBrian Somers void
254503a7782SBrian Somers ipcp_Setup(struct ipcp *ipcp)
255503a7782SBrian Somers {
256503a7782SBrian Somers   int pos;
257503a7782SBrian Somers 
258503a7782SBrian Somers   ipcp->fsm.open_mode = 0;
2595454ccd9SBrian Somers   ipcp->fsm.maxconfig = 10;
260503a7782SBrian Somers 
261503a7782SBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list)) {
262503a7782SBrian Somers     if (ipcp->my_ifip.s_addr != INADDR_ANY &&
263503a7782SBrian Somers         (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1)
264503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos);
265503a7782SBrian Somers     else
266503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
267503a7782SBrian Somers     ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
268503a7782SBrian Somers     ipcp->cfg.peer_range.width = 32;
269503a7782SBrian Somers   }
270503a7782SBrian Somers 
271503a7782SBrian Somers   ipcp->heis1172 = 0;
272503a7782SBrian Somers 
273503a7782SBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
274503a7782SBrian Somers   ipcp->peer_compproto = 0;
2751ae349f5Scvs2svn 
2768390b576SBrian Somers   if (ipcp->cfg.HaveTriggerAddress) {
2771ae349f5Scvs2svn     /*
2781ae349f5Scvs2svn      * Some implementations of PPP require that we send a
2791ae349f5Scvs2svn      * *special* value as our address, even though the rfc specifies
2801ae349f5Scvs2svn      * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
2811ae349f5Scvs2svn      */
282503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.TriggerAddress;
28329e275ceSBrian Somers     LogPrintf(LogIPCP, "Using trigger address %s\n",
284503a7782SBrian Somers               inet_ntoa(ipcp->cfg.TriggerAddress));
2858390b576SBrian Somers   } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
2868390b576SBrian Somers              (ipcp->cfg.my_range.ipaddr.s_addr &
2878390b576SBrian Somers               ipcp->cfg.my_range.mask.s_addr))
2888390b576SBrian Somers     /*
2898390b576SBrian Somers      * Otherwise, if we've been assigned an IP number before, we really
2908390b576SBrian Somers      * want to keep the same IP number so that we can keep any existing
2918390b576SBrian Somers      * connections that are bound to that IP.
2928390b576SBrian Somers      */
2938390b576SBrian Somers     ipcp->my_ip = ipcp->my_ifip;
2948390b576SBrian Somers   else
295503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
29629e275ceSBrian Somers 
2971ae349f5Scvs2svn   if (Enabled(ConfVjcomp))
298503a7782SBrian Somers     ipcp->my_compproto = (PROTO_VJCOMP << 16) +
299503a7782SBrian Somers                          ((ipcp->cfg.VJInitSlots - 1) << 8) +
300503a7782SBrian Somers                          ipcp->cfg.VJInitComp;
3011ae349f5Scvs2svn   else
302503a7782SBrian Somers     ipcp->my_compproto = 0;
303eaa4df37SBrian Somers   sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.VJInitSlots - 1);
30429e275ceSBrian Somers 
305503a7782SBrian Somers   ipcp->peer_reject = 0;
306503a7782SBrian Somers   ipcp->my_reject = 0;
307503a7782SBrian Somers 
308503a7782SBrian Somers   throughput_init(&ipcp->throughput);
3091ae349f5Scvs2svn }
3101ae349f5Scvs2svn 
311455aabc3SBrian Somers static int
31230c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
31330c2f2ffSBrian Somers                   struct in_addr hisaddr, int silent)
314455aabc3SBrian Somers {
315455aabc3SBrian Somers   struct sockaddr_in *sock_in;
316455aabc3SBrian Somers   int s;
317455aabc3SBrian Somers   u_long mask, addr;
318455aabc3SBrian Somers   struct ifaliasreq ifra;
319455aabc3SBrian Somers 
320455aabc3SBrian Somers   /* If given addresses are alreay set, then ignore this request */
32130c2f2ffSBrian Somers   if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr &&
32230c2f2ffSBrian Somers       bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr)
323455aabc3SBrian Somers     return 0;
324455aabc3SBrian Somers 
32530c2f2ffSBrian Somers   IpcpCleanInterface(&bundle->ncp.ipcp.fsm);
32668a0f0ccSBrian Somers 
327455aabc3SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
328455aabc3SBrian Somers   if (s < 0) {
329455aabc3SBrian Somers     LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
330455aabc3SBrian Somers     return (-1);
331455aabc3SBrian Somers   }
332455aabc3SBrian Somers 
333455aabc3SBrian Somers   memset(&ifra, '\0', sizeof ifra);
334455aabc3SBrian Somers   strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1);
335455aabc3SBrian Somers   ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
336455aabc3SBrian Somers 
337455aabc3SBrian Somers   /* Set interface address */
338455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
339455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
340455aabc3SBrian Somers   sock_in->sin_addr = myaddr;
341455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
342455aabc3SBrian Somers 
343455aabc3SBrian Somers   /* Set destination address */
344455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
345455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
346455aabc3SBrian Somers   sock_in->sin_addr = hisaddr;
347455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
348455aabc3SBrian Somers 
349455aabc3SBrian Somers   addr = ntohl(myaddr.s_addr);
350455aabc3SBrian Somers   if (IN_CLASSA(addr))
351455aabc3SBrian Somers     mask = IN_CLASSA_NET;
352455aabc3SBrian Somers   else if (IN_CLASSB(addr))
353455aabc3SBrian Somers     mask = IN_CLASSB_NET;
354455aabc3SBrian Somers   else
355455aabc3SBrian Somers     mask = IN_CLASSC_NET;
356455aabc3SBrian Somers 
357455aabc3SBrian Somers   /* if subnet mask is given, use it instead of class mask */
35830c2f2ffSBrian Somers   if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY &&
35930c2f2ffSBrian Somers       (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask)
36030c2f2ffSBrian Somers     mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr);
361455aabc3SBrian Somers 
362455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
363455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
364455aabc3SBrian Somers   sock_in->sin_addr.s_addr = htonl(mask);
365455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
366455aabc3SBrian Somers 
367455aabc3SBrian Somers   if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
368455aabc3SBrian Somers     if (!silent)
369455aabc3SBrian Somers       LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n",
370455aabc3SBrian Somers 		strerror(errno));
371455aabc3SBrian Somers     close(s);
372455aabc3SBrian Somers     return (-1);
373455aabc3SBrian Somers   }
374455aabc3SBrian Somers 
37530c2f2ffSBrian Somers   bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr;
37630c2f2ffSBrian Somers   bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr;
377455aabc3SBrian Somers 
378455aabc3SBrian Somers   if (Enabled(ConfProxy))
37930c2f2ffSBrian Somers     sifproxyarp(bundle, bundle->ncp.ipcp.peer_ifip, s);
380455aabc3SBrian Somers 
381455aabc3SBrian Somers   close(s);
382455aabc3SBrian Somers   return (0);
383455aabc3SBrian Somers }
384455aabc3SBrian Somers 
385455aabc3SBrian Somers static struct in_addr
38630c2f2ffSBrian Somers ChooseHisAddr(struct bundle *bundle, const struct in_addr gw)
387455aabc3SBrian Somers {
388455aabc3SBrian Somers   struct in_addr try;
389455aabc3SBrian Somers   int f;
390455aabc3SBrian Somers 
3915828db6dSBrian Somers   for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
3925828db6dSBrian Somers     try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
393455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
394455aabc3SBrian Somers               f, inet_ntoa(try));
39530c2f2ffSBrian Somers     if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
396455aabc3SBrian Somers       LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
397455aabc3SBrian Somers                 inet_ntoa(try));
398455aabc3SBrian Somers       break;
399455aabc3SBrian Somers     }
400455aabc3SBrian Somers   }
401455aabc3SBrian Somers 
4025828db6dSBrian Somers   if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
403455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
404455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
405455aabc3SBrian Somers   }
406455aabc3SBrian Somers 
407455aabc3SBrian Somers   return try;
408455aabc3SBrian Somers }
409455aabc3SBrian Somers 
4101ae349f5Scvs2svn static void
4111ae349f5Scvs2svn IpcpInitRestartCounter(struct fsm * fp)
4121ae349f5Scvs2svn {
4137308ec68SBrian Somers   /* Set fsm timer load */
414cd9647a1SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
415cd9647a1SBrian Somers 
416cd9647a1SBrian Somers   fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS;
4171ae349f5Scvs2svn   fp->restart = 5;
4181ae349f5Scvs2svn }
4191ae349f5Scvs2svn 
4201ae349f5Scvs2svn static void
4211ae349f5Scvs2svn IpcpSendConfigReq(struct fsm *fp)
4221ae349f5Scvs2svn {
4237308ec68SBrian Somers   /* Send config REQ please */
4248c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
425aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
4262267893fSBrian Somers   u_char buff[12];
4272267893fSBrian Somers   struct lcp_opt *o;
4281ae349f5Scvs2svn 
4292267893fSBrian Somers   o = (struct lcp_opt *)buff;
43030c2f2ffSBrian Somers 
43183d1af55SBrian Somers   if ((p && !Physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
4322267893fSBrian Somers     *(u_int32_t *)o->data = ipcp->my_ip.s_addr;
4332267893fSBrian Somers     INC_LCP_OPT(TY_IPADDR, 6, o);
4341ae349f5Scvs2svn   }
4351ae349f5Scvs2svn 
4362267893fSBrian Somers   if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO))
43783d1af55SBrian Somers     if (ipcp->heis1172) {
4382267893fSBrian Somers       *(u_short *)o->data = htons(PROTO_VJCOMP);
4392267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 4, o);
4401ae349f5Scvs2svn     } else {
4412267893fSBrian Somers       *(u_long *)o->data = htonl(ipcp->my_compproto);
4422267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 6, o);
4431ae349f5Scvs2svn     }
4442267893fSBrian Somers 
4452267893fSBrian Somers   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
4461ae349f5Scvs2svn }
4471ae349f5Scvs2svn 
4481ae349f5Scvs2svn static void
4492267893fSBrian Somers IpcpSentTerminateReq(struct fsm * fp)
4501ae349f5Scvs2svn {
4517308ec68SBrian Somers   /* Term REQ just sent by FSM */
4521ae349f5Scvs2svn }
4531ae349f5Scvs2svn 
4541ae349f5Scvs2svn static void
4552267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id)
4561ae349f5Scvs2svn {
4577308ec68SBrian Somers   /* Send Term ACK please */
4582267893fSBrian Somers   FsmOutput(fp, CODE_TERMACK, id, NULL, 0);
4591ae349f5Scvs2svn }
4601ae349f5Scvs2svn 
4611ae349f5Scvs2svn static void
4621ae349f5Scvs2svn IpcpLayerStart(struct fsm * fp)
4631ae349f5Scvs2svn {
4647308ec68SBrian Somers   /* We're about to start up ! */
4651ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerStart.\n");
466455aabc3SBrian Somers 
467455aabc3SBrian Somers   /* This is where we should be setting up the interface in AUTO mode */
4681ae349f5Scvs2svn }
4691ae349f5Scvs2svn 
4701ae349f5Scvs2svn static void
4711ae349f5Scvs2svn IpcpLayerFinish(struct fsm *fp)
4721ae349f5Scvs2svn {
4737308ec68SBrian Somers   /* We're now down */
4741ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerFinish.\n");
4751ae349f5Scvs2svn }
4761ae349f5Scvs2svn 
47768a0f0ccSBrian Somers void
47868a0f0ccSBrian Somers IpcpCleanInterface(struct fsm *fp)
47968a0f0ccSBrian Somers {
48068a0f0ccSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
48168a0f0ccSBrian Somers   struct ifaliasreq ifra;
48268a0f0ccSBrian Somers   struct sockaddr_in *me, *peer;
48368a0f0ccSBrian Somers   int s;
48468a0f0ccSBrian Somers 
48568a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
48668a0f0ccSBrian Somers   if (s < 0) {
48768a0f0ccSBrian Somers     LogPrintf(LogERROR, "IpcpCleanInterface: socket: %s\n", strerror(errno));
48868a0f0ccSBrian Somers     return;
48968a0f0ccSBrian Somers   }
49068a0f0ccSBrian Somers 
49168a0f0ccSBrian Somers   if (Enabled(ConfProxy))
492503a7782SBrian Somers     cifproxyarp(fp->bundle, ipcp->peer_ifip, s);
49368a0f0ccSBrian Somers 
494503a7782SBrian Somers   if (ipcp->my_ifip.s_addr != INADDR_ANY ||
495503a7782SBrian Somers       ipcp->peer_ifip.s_addr != INADDR_ANY) {
49668a0f0ccSBrian Somers     memset(&ifra, '\0', sizeof ifra);
49768a0f0ccSBrian Somers     strncpy(ifra.ifra_name, fp->bundle->ifname, sizeof ifra.ifra_name - 1);
49868a0f0ccSBrian Somers     ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
49968a0f0ccSBrian Somers     me = (struct sockaddr_in *)&ifra.ifra_addr;
50068a0f0ccSBrian Somers     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
50168a0f0ccSBrian Somers     me->sin_family = peer->sin_family = AF_INET;
50268a0f0ccSBrian Somers     me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
503503a7782SBrian Somers     me->sin_addr = ipcp->my_ifip;
504503a7782SBrian Somers     peer->sin_addr = ipcp->peer_ifip;
50568a0f0ccSBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
50668a0f0ccSBrian Somers       LogPrintf(LogERROR, "IpcpCleanInterface: ioctl(SIOCDIFADDR): %s\n",
50768a0f0ccSBrian Somers                 strerror(errno));
50868a0f0ccSBrian Somers       close(s);
50968a0f0ccSBrian Somers     }
510503a7782SBrian Somers     ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY;
51168a0f0ccSBrian Somers   }
51268a0f0ccSBrian Somers 
51368a0f0ccSBrian Somers   close(s);
51468a0f0ccSBrian Somers }
51568a0f0ccSBrian Somers 
5161ae349f5Scvs2svn static void
5171ae349f5Scvs2svn IpcpLayerDown(struct fsm *fp)
5181ae349f5Scvs2svn {
5197308ec68SBrian Somers   /* About to come down */
520aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
521455aabc3SBrian Somers   const char *s;
522455aabc3SBrian Somers 
523503a7782SBrian Somers   s = inet_ntoa(ipcp->peer_ifip);
524455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerDown: %s\n", s);
525455aabc3SBrian Somers 
52683d1af55SBrian Somers   throughput_stop(&ipcp->throughput);
52783d1af55SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
528455aabc3SBrian Somers   /*
529455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
530455aabc3SBrian Somers    * associate executable sections in files with events.
531455aabc3SBrian Somers    */
532b6217683SBrian Somers   if (SelectSystem(fp->bundle, s, LINKDOWNFILE, NULL) < 0)
533455aabc3SBrian Somers     if (GetLabel()) {
534b6217683SBrian Somers        if (SelectSystem(fp->bundle, GetLabel(), LINKDOWNFILE, NULL) < 0)
535b6217683SBrian Somers        SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE, NULL);
536455aabc3SBrian Somers     } else
537b6217683SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE, NULL);
538455aabc3SBrian Somers 
53968a0f0ccSBrian Somers   if (!(mode & MODE_AUTO))
54068a0f0ccSBrian Somers     IpcpCleanInterface(fp);
5411ae349f5Scvs2svn }
5421ae349f5Scvs2svn 
5431ae349f5Scvs2svn static void
5441ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp)
5451ae349f5Scvs2svn {
5467308ec68SBrian Somers   /* We're now up */
547aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
5481ae349f5Scvs2svn   char tbuff[100];
5491ae349f5Scvs2svn 
5502267893fSBrian Somers   LogPrintf(LogIPCP, "IpcpLayerUp.\n");
551503a7782SBrian Somers   snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
552455aabc3SBrian Somers   LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n",
553503a7782SBrian Somers 	    tbuff, inet_ntoa(ipcp->peer_ip));
5541ae349f5Scvs2svn 
555503a7782SBrian Somers   if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
556eaa4df37SBrian Somers     sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
5571ae349f5Scvs2svn 
55830c2f2ffSBrian Somers   if (ipcp_SetIPaddress(fp->bundle, ipcp->my_ip,
55930c2f2ffSBrian Somers                         ipcp->peer_ip, 0) < 0) {
5601ae349f5Scvs2svn     LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
5611ae349f5Scvs2svn     return;
5621ae349f5Scvs2svn   }
563455aabc3SBrian Somers 
5641ae349f5Scvs2svn #ifndef NOALIAS
5651ae349f5Scvs2svn   if (mode & MODE_ALIAS)
566503a7782SBrian Somers     VarPacketAliasSetAddress(ipcp->my_ip);
5671ae349f5Scvs2svn #endif
568455aabc3SBrian Somers 
569455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerUp: %s\n",
570503a7782SBrian Somers             inet_ntoa(ipcp->peer_ifip));
571455aabc3SBrian Somers 
572455aabc3SBrian Somers   /*
573455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
574455aabc3SBrian Somers    * associate executable sections in files with events.
575455aabc3SBrian Somers    */
576b6217683SBrian Somers   if (SelectSystem(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, NULL) < 0)
577455aabc3SBrian Somers     if (GetLabel()) {
578b6217683SBrian Somers       if (SelectSystem(fp->bundle, GetLabel(), LINKUPFILE, NULL) < 0)
579b6217683SBrian Somers         SelectSystem(fp->bundle, "MYADDR", LINKUPFILE, NULL);
580455aabc3SBrian Somers     } else
581b6217683SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKUPFILE, NULL);
582455aabc3SBrian Somers 
5833b0f8d2eSBrian Somers   throughput_start(&ipcp->throughput, "IPCP throughput");
584b6217683SBrian Somers   bundle_DisplayPrompt(fp->bundle);
5851ae349f5Scvs2svn }
5861ae349f5Scvs2svn 
5871ae349f5Scvs2svn static int
5881ae349f5Scvs2svn AcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
5891ae349f5Scvs2svn {
5907308ec68SBrian Somers   /* Is the given IP in the given range ? */
5911ae349f5Scvs2svn   LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr));
5921ae349f5Scvs2svn   LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr));
5931ae349f5Scvs2svn   LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr));
5941ae349f5Scvs2svn   LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange->
5951ae349f5Scvs2svn 		  mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr));
5961ae349f5Scvs2svn   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
5971ae349f5Scvs2svn     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
5981ae349f5Scvs2svn }
5991ae349f5Scvs2svn 
6001ae349f5Scvs2svn static void
60130c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
60230c2f2ffSBrian Somers                  struct fsm_decode *dec)
6031ae349f5Scvs2svn {
6047308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
605aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
6061ae349f5Scvs2svn   int type, length;
6071ae349f5Scvs2svn   u_long *lp, compproto;
6081ae349f5Scvs2svn   struct compreq *pcomp;
6091ae349f5Scvs2svn   struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
61030c2f2ffSBrian Somers   char tbuff[100], tbuff2[100];
6111ae349f5Scvs2svn 
6121ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
6131ae349f5Scvs2svn     type = *cp;
6141ae349f5Scvs2svn     length = cp[1];
6151ae349f5Scvs2svn     if (type < NCFTYPES)
6161ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
6171ae349f5Scvs2svn     else if (type > 128 && type < 128 + NCFTYPES128)
6181ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
6191ae349f5Scvs2svn     else
6201ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
6211ae349f5Scvs2svn 
6221ae349f5Scvs2svn     switch (type) {
6231ae349f5Scvs2svn     case TY_IPADDR:		/* RFC1332 */
6241ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6251ae349f5Scvs2svn       ipaddr.s_addr = *lp;
6261ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
6271ae349f5Scvs2svn 
6281ae349f5Scvs2svn       switch (mode_type) {
6291ae349f5Scvs2svn       case MODE_REQ:
630503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
6311ae349f5Scvs2svn           if (ipaddr.s_addr == INADDR_ANY ||
632503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
63330c2f2ffSBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
63430c2f2ffSBrian Somers                                 ipaddr, 1)) {
6351ae349f5Scvs2svn             LogPrintf(LogIPCP, "%s: Address invalid or already in use\n",
6361ae349f5Scvs2svn                       inet_ntoa(ipaddr));
6378390b576SBrian Somers             if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0)
6388390b576SBrian Somers               /*
6398390b576SBrian Somers                * If we've already got a valid address configured for the peer
6408390b576SBrian Somers                * (in AUTO mode), try NAKing with that so that we don't
6418390b576SBrian Somers                * have to upset things too much.
6428390b576SBrian Somers                */
6438390b576SBrian Somers               ipcp->peer_ip = ipcp->peer_ifip;
6448390b576SBrian Somers             else
6458390b576SBrian Somers               /* Just pick an IP number from our list */
646503a7782SBrian Somers               ipcp->peer_ip = ChooseHisAddr
64730c2f2ffSBrian Somers                 (fp->bundle, ipcp->cfg.my_range.ipaddr);
6488390b576SBrian Somers 
649503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
65030c2f2ffSBrian Somers 	      memcpy(dec->rejend, cp, length);
65130c2f2ffSBrian Somers 	      dec->rejend += length;
6521ae349f5Scvs2svn             } else {
65330c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
65430c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
65530c2f2ffSBrian Somers 	      dec->nakend += length;
6561ae349f5Scvs2svn             }
6571ae349f5Scvs2svn 	    break;
6581ae349f5Scvs2svn           }
659503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
6601ae349f5Scvs2svn 	  /*
6618390b576SBrian Somers 	   * If destination address is not acceptable, NAK with what we
6621ae349f5Scvs2svn 	   * want to use.
6631ae349f5Scvs2svn 	   */
66430c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
6658390b576SBrian Somers           if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) ==
6668390b576SBrian Somers              (ipcp->cfg.peer_range.ipaddr.s_addr &
6678390b576SBrian Somers               ipcp->cfg.peer_range.mask.s_addr))
6688390b576SBrian Somers             /* We prefer the already-configured address */
6698390b576SBrian Somers 	    memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2);
6708390b576SBrian Somers           else
67130c2f2ffSBrian Somers 	    memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
67230c2f2ffSBrian Somers 	  dec->nakend += length;
6731ae349f5Scvs2svn 	  break;
6741ae349f5Scvs2svn 	}
675503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
67630c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
67730c2f2ffSBrian Somers 	dec->ackend += length;
6781ae349f5Scvs2svn 	break;
6791ae349f5Scvs2svn       case MODE_NAK:
680503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
6811ae349f5Scvs2svn 	  /* Use address suggested by peer */
6821ae349f5Scvs2svn 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
683503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
6841ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
685503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
6861ae349f5Scvs2svn 	} else {
6878390b576SBrian Somers 	  LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogPHASE,
6888390b576SBrian Somers                     "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
68983d1af55SBrian Somers           FsmClose(&ipcp->fsm);
6901ae349f5Scvs2svn 	}
6911ae349f5Scvs2svn 	break;
6921ae349f5Scvs2svn       case MODE_REJ:
693503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
6941ae349f5Scvs2svn 	break;
6951ae349f5Scvs2svn       }
6961ae349f5Scvs2svn       break;
6971ae349f5Scvs2svn     case TY_COMPPROTO:
6981ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6991ae349f5Scvs2svn       compproto = htonl(*lp);
7001ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
7011ae349f5Scvs2svn 
7021ae349f5Scvs2svn       switch (mode_type) {
7031ae349f5Scvs2svn       case MODE_REQ:
7041ae349f5Scvs2svn 	if (!Acceptable(ConfVjcomp)) {
70530c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
70630c2f2ffSBrian Somers 	  dec->rejend += length;
7071ae349f5Scvs2svn 	} else {
7081ae349f5Scvs2svn 	  pcomp = (struct compreq *) (cp + 2);
7091ae349f5Scvs2svn 	  switch (length) {
7101ae349f5Scvs2svn 	  case 4:		/* RFC1172 */
7111ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
7121ae349f5Scvs2svn 	      LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
71383d1af55SBrian Somers 	      ipcp->heis1172 = 1;
714503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
71530c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
71630c2f2ffSBrian Somers 	      dec->ackend += length;
7171ae349f5Scvs2svn 	    } else {
71830c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
7191ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
72030c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, 2);
72130c2f2ffSBrian Somers 	      dec->nakend += length;
7221ae349f5Scvs2svn 	    }
7231ae349f5Scvs2svn 	    break;
7241ae349f5Scvs2svn 	  case 6:		/* RFC1332 */
7251ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
726503a7782SBrian Somers 		&& pcomp->slots <= MAX_VJ_STATES
727503a7782SBrian Somers                 && pcomp->slots >= MIN_VJ_STATES) {
728503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
72983d1af55SBrian Somers 	      ipcp->heis1172 = 0;
73030c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
73130c2f2ffSBrian Somers 	      dec->ackend += length;
7321ae349f5Scvs2svn 	    } else {
73330c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
7341ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
735503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
7361ae349f5Scvs2svn 	      pcomp->compcid = 0;
73730c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
73830c2f2ffSBrian Somers 	      dec->nakend += length;
7391ae349f5Scvs2svn 	    }
7401ae349f5Scvs2svn 	    break;
7411ae349f5Scvs2svn 	  default:
74230c2f2ffSBrian Somers 	    memcpy(dec->rejend, cp, length);
74330c2f2ffSBrian Somers 	    dec->rejend += length;
7441ae349f5Scvs2svn 	    break;
7451ae349f5Scvs2svn 	  }
7461ae349f5Scvs2svn 	}
7471ae349f5Scvs2svn 	break;
7481ae349f5Scvs2svn       case MODE_NAK:
7491ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
750503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
751503a7782SBrian Somers 	ipcp->my_compproto = compproto;
7521ae349f5Scvs2svn 	break;
7531ae349f5Scvs2svn       case MODE_REJ:
754503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
7551ae349f5Scvs2svn 	break;
7561ae349f5Scvs2svn       }
7571ae349f5Scvs2svn       break;
7581ae349f5Scvs2svn     case TY_IPADDRS:		/* RFC1172 */
7591ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
7601ae349f5Scvs2svn       ipaddr.s_addr = *lp;
7611ae349f5Scvs2svn       lp = (u_long *) (cp + 6);
7621ae349f5Scvs2svn       dstipaddr.s_addr = *lp;
7631ae349f5Scvs2svn       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
7641ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
7651ae349f5Scvs2svn 
7661ae349f5Scvs2svn       switch (mode_type) {
7671ae349f5Scvs2svn       case MODE_REQ:
768503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
769503a7782SBrian Somers 	ipcp->my_ip = dstipaddr;
77030c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
77130c2f2ffSBrian Somers 	dec->ackend += length;
7721ae349f5Scvs2svn 	break;
7731ae349f5Scvs2svn       case MODE_NAK:
7741ae349f5Scvs2svn         snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
775503a7782SBrian Somers 		 inet_ntoa(ipcp->my_ip));
7761ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
777503a7782SBrian Somers 	ipcp->my_ip = ipaddr;
778503a7782SBrian Somers 	ipcp->peer_ip = dstipaddr;
7791ae349f5Scvs2svn 	break;
7801ae349f5Scvs2svn       case MODE_REJ:
781503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
7821ae349f5Scvs2svn 	break;
7831ae349f5Scvs2svn       }
7841ae349f5Scvs2svn       break;
7851ae349f5Scvs2svn 
7861ae349f5Scvs2svn       /*
7871ae349f5Scvs2svn        * MS extensions for MS's PPP
7881ae349f5Scvs2svn        */
7891ae349f5Scvs2svn 
7901ae349f5Scvs2svn #ifndef NOMSEXT
7911ae349f5Scvs2svn     case TY_PRIMARY_DNS:	/* MS PPP DNS negotiation hack */
7921ae349f5Scvs2svn     case TY_SECONDARY_DNS:
79330c2f2ffSBrian Somers       switch (mode_type) {
79430c2f2ffSBrian Somers       case MODE_REQ:
7951ae349f5Scvs2svn         if (!Enabled(ConfMSExt)) {
7961ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n");
79783d1af55SBrian Somers 	  ipcp->my_reject |= (1 << type);
79830c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
79930c2f2ffSBrian Somers 	  dec->rejend += length;
8001ae349f5Scvs2svn 	  break;
8011ae349f5Scvs2svn         }
8021ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
8031ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
804503a7782SBrian Somers 	ms_info_req.s_addr = ipcp->cfg.ns_entries
80529e275ceSBrian Somers           [(type - TY_PRIMARY_DNS) ? 1 : 0].s_addr;
8061ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
8071ae349f5Scvs2svn 
8081ae349f5Scvs2svn 	  /*
8091ae349f5Scvs2svn 	   * So the client has got the DNS stuff wrong (first request) so
8101ae349f5Scvs2svn 	   * we'll tell 'em how it is
8111ae349f5Scvs2svn 	   */
81230c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
8131ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n",
8142267893fSBrian Somers 		    type, inet_ntoa(dnsstuff), inet_ntoa(ms_info_req));
81530c2f2ffSBrian Somers 	  memcpy(dec->nakend+2, &ms_info_req, length);
81630c2f2ffSBrian Somers 	  dec->nakend += length;
8171ae349f5Scvs2svn 	  break;
8181ae349f5Scvs2svn 	}
8191ae349f5Scvs2svn 
8201ae349f5Scvs2svn 	/*
8211ae349f5Scvs2svn 	 * Otherwise they have it right (this time) so we send a ack packet
8221ae349f5Scvs2svn 	 * back confirming it... end of story
8231ae349f5Scvs2svn 	 */
8241ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n",
8252267893fSBrian Somers 		  type, inet_ntoa(ms_info_req));
82630c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
82730c2f2ffSBrian Somers 	dec->ackend += length;
8281ae349f5Scvs2svn 	break;
8291ae349f5Scvs2svn       case MODE_NAK:		/* what does this mean?? */
8301ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type);
8311ae349f5Scvs2svn 	break;
8321ae349f5Scvs2svn       case MODE_REJ:		/* confused?? me to :) */
8331ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type);
8341ae349f5Scvs2svn 	break;
8351ae349f5Scvs2svn       }
8361ae349f5Scvs2svn       break;
8371ae349f5Scvs2svn 
8381ae349f5Scvs2svn     case TY_PRIMARY_NBNS:	/* MS PPP NetBIOS nameserver hack */
8391ae349f5Scvs2svn     case TY_SECONDARY_NBNS:
84030c2f2ffSBrian Somers       switch (mode_type) {
84130c2f2ffSBrian Somers       case MODE_REQ:
8421ae349f5Scvs2svn         if (!Enabled(ConfMSExt)) {
8431ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n");
84483d1af55SBrian Somers 	  ipcp->my_reject |= (1 << type);
84530c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
84630c2f2ffSBrian Somers 	  dec->rejend += length;
8471ae349f5Scvs2svn 	  break;
8481ae349f5Scvs2svn         }
8491ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
8501ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
851503a7782SBrian Somers 	ms_info_req.s_addr = ipcp->cfg.nbns_entries
85229e275ceSBrian Somers           [(type - TY_PRIMARY_NBNS) ? 1 : 0].s_addr;
8531ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
85430c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
85530c2f2ffSBrian Somers 	  memcpy(dec->nakend+2, &ms_info_req.s_addr, length);
8561ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n",
8572267893fSBrian Somers 		    type, inet_ntoa(dnsstuff), inet_ntoa(ms_info_req));
85830c2f2ffSBrian Somers 	  dec->nakend += length;
8591ae349f5Scvs2svn 	  break;
8601ae349f5Scvs2svn 	}
8611ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n",
8622267893fSBrian Somers 		  type, inet_ntoa(ms_info_req));
86330c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
86430c2f2ffSBrian Somers 	dec->ackend += length;
8651ae349f5Scvs2svn 	break;
8661ae349f5Scvs2svn       case MODE_NAK:
8671ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
8681ae349f5Scvs2svn 	break;
8691ae349f5Scvs2svn       case MODE_REJ:
8701ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
8711ae349f5Scvs2svn 	break;
8721ae349f5Scvs2svn       }
8731ae349f5Scvs2svn       break;
8741ae349f5Scvs2svn 
8751ae349f5Scvs2svn #endif
8761ae349f5Scvs2svn 
8771ae349f5Scvs2svn     default:
87830c2f2ffSBrian Somers       if (mode_type != MODE_NOP) {
87983d1af55SBrian Somers         ipcp->my_reject |= (1 << type);
88030c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
88130c2f2ffSBrian Somers         dec->rejend += length;
88230c2f2ffSBrian Somers       }
8831ae349f5Scvs2svn       break;
8841ae349f5Scvs2svn     }
8851ae349f5Scvs2svn     plen -= length;
8861ae349f5Scvs2svn     cp += length;
8871ae349f5Scvs2svn   }
8881ae349f5Scvs2svn }
8891ae349f5Scvs2svn 
8901ae349f5Scvs2svn void
8915828db6dSBrian Somers IpcpInput(struct ipcp *ipcp, struct mbuf * bp)
8921ae349f5Scvs2svn {
8937308ec68SBrian Somers   /* Got PROTO_IPCP from link */
8945828db6dSBrian Somers   FsmInput(&ipcp->fsm, bp);
8951ae349f5Scvs2svn }
8961ae349f5Scvs2svn 
8971ae349f5Scvs2svn int
8987a6f8720SBrian Somers UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
8991ae349f5Scvs2svn {
9005828db6dSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
9015828db6dSBrian Somers 
9027308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
9035828db6dSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
9045828db6dSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
9051ae349f5Scvs2svn   if (strpbrk(hisaddr, ",-")) {
9065828db6dSBrian Somers     iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
9075828db6dSBrian Somers     if (iplist_isvalid(&ipcp->cfg.peer_list)) {
9085828db6dSBrian Somers       iplist_setrandpos(&ipcp->cfg.peer_list);
90930c2f2ffSBrian Somers       ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
9105828db6dSBrian Somers       if (ipcp->peer_ip.s_addr == INADDR_ANY) {
9115828db6dSBrian Somers         LogPrintf(LogWARN, "%s: None available !\n",
9125828db6dSBrian Somers                   ipcp->cfg.peer_list.src);
9131ae349f5Scvs2svn         return(0);
9141ae349f5Scvs2svn       }
9155828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
9165828db6dSBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
9175828db6dSBrian Somers       ipcp->cfg.peer_range.width = 32;
9181ae349f5Scvs2svn     } else {
9191ae349f5Scvs2svn       LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr);
9201ae349f5Scvs2svn       return 0;
9211ae349f5Scvs2svn     }
9225828db6dSBrian Somers   } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr,
9235828db6dSBrian Somers 		       &ipcp->cfg.peer_range.mask,
9245828db6dSBrian Somers                        &ipcp->cfg.peer_range.width) != 0) {
9255828db6dSBrian Somers     ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
9261ae349f5Scvs2svn 
92730c2f2ffSBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
92830c2f2ffSBrian Somers                                      ipcp->cfg.peer_range.ipaddr, 0) < 0) {
9295828db6dSBrian Somers       ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
9305828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
9311ae349f5Scvs2svn       return 0;
9321ae349f5Scvs2svn     }
9331ae349f5Scvs2svn   } else
9341ae349f5Scvs2svn     return 0;
9351ae349f5Scvs2svn 
9361ae349f5Scvs2svn   return 1;
9371ae349f5Scvs2svn }
938