xref: /freebsd/usr.sbin/ppp/ipcp.c (revision 3b0f8d2ed641ceeded11c0d3f253b0cacbf00880)
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  *
203b0f8d2eSBrian Somers  * $Id: ipcp.c,v 1.50.2.27 1998/03/24 18:47:10 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 {
1455828db6dSBrian Somers   prompt_Printf(&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) {
14885b542cfSBrian Somers     prompt_Printf(&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));
15185b542cfSBrian Somers     prompt_Printf(&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 
15685b542cfSBrian Somers   prompt_Printf(&prompt, "\nDefaults:\n");
15785b542cfSBrian Somers   prompt_Printf(&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))
16185b542cfSBrian Somers     prompt_Printf(&prompt, " His Address:            %s\n",
1625828db6dSBrian Somers             arg->bundle->ncp.ipcp.cfg.peer_list.src);
1631ae349f5Scvs2svn   else
16485b542cfSBrian Somers     prompt_Printf(&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)
16885b542cfSBrian Somers     prompt_Printf(&prompt, " Negotiation(trigger):   %s\n",
1695828db6dSBrian Somers             inet_ntoa(arg->bundle->ncp.ipcp.cfg.TriggerAddress));
1701ae349f5Scvs2svn   else
17185b542cfSBrian Somers     prompt_Printf(&prompt, " Negotiation(trigger):   MYADDR\n");
172503a7782SBrian Somers   prompt_Printf(&prompt, " Initial VJ slots:       %d\n",
1735828db6dSBrian Somers                 arg->bundle->ncp.ipcp.cfg.VJInitSlots);
17485b542cfSBrian Somers   prompt_Printf(&prompt, " Initial VJ compression: %s\n",
1755828db6dSBrian Somers           arg->bundle->ncp.ipcp.cfg.VJInitComp ? "on" : "off");
1761ae349f5Scvs2svn 
17785b542cfSBrian Somers   prompt_Printf(&prompt, "\n");
1785828db6dSBrian Somers   throughput_disp(&arg->bundle->ncp.ipcp.throughput);
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 
236503a7782SBrian Somers   ipcp->cfg.ns_entries[0].s_addr = INADDR_ANY;
237503a7782SBrian Somers   ipcp->cfg.ns_entries[1].s_addr = INADDR_ANY;
238503a7782SBrian Somers   ipcp->cfg.nbns_entries[0].s_addr = INADDR_ANY;
239503a7782SBrian Somers   ipcp->cfg.nbns_entries[1].s_addr = INADDR_ANY;
240503a7782SBrian Somers 
241eaa4df37SBrian Somers   memset(&ipcp->vj, '\0', sizeof ipcp->vj);
242eaa4df37SBrian Somers 
243503a7782SBrian Somers   ipcp->my_ifip.s_addr = INADDR_ANY;
244503a7782SBrian Somers   ipcp->peer_ifip.s_addr = INADDR_ANY;
245503a7782SBrian Somers 
246503a7782SBrian Somers   ipcp_Setup(ipcp);
247503a7782SBrian Somers }
248503a7782SBrian Somers 
249503a7782SBrian Somers void
250503a7782SBrian Somers ipcp_Setup(struct ipcp *ipcp)
251503a7782SBrian Somers {
252503a7782SBrian Somers   int pos;
253503a7782SBrian Somers 
254503a7782SBrian Somers   ipcp->fsm.open_mode = 0;
2555454ccd9SBrian Somers   ipcp->fsm.maxconfig = 10;
256503a7782SBrian Somers 
257503a7782SBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list)) {
258503a7782SBrian Somers     if (ipcp->my_ifip.s_addr != INADDR_ANY &&
259503a7782SBrian Somers         (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1)
260503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos);
261503a7782SBrian Somers     else
262503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
263503a7782SBrian Somers     ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
264503a7782SBrian Somers     ipcp->cfg.peer_range.width = 32;
265503a7782SBrian Somers   }
266503a7782SBrian Somers 
267503a7782SBrian Somers   ipcp->heis1172 = 0;
268503a7782SBrian Somers 
269503a7782SBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
270503a7782SBrian Somers   ipcp->peer_compproto = 0;
2711ae349f5Scvs2svn 
2721ae349f5Scvs2svn   /*
2731ae349f5Scvs2svn    * Some implementations of PPP require that we send a
2741ae349f5Scvs2svn    * *special* value as our address, even though the rfc specifies
2751ae349f5Scvs2svn    * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
2761ae349f5Scvs2svn    */
277503a7782SBrian Somers   if (ipcp->cfg.HaveTriggerAddress) {
278503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.TriggerAddress;
27929e275ceSBrian Somers     LogPrintf(LogIPCP, "Using trigger address %s\n",
280503a7782SBrian Somers               inet_ntoa(ipcp->cfg.TriggerAddress));
281503a7782SBrian Somers   } else
282503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
28329e275ceSBrian Somers 
2841ae349f5Scvs2svn   if (Enabled(ConfVjcomp))
285503a7782SBrian Somers     ipcp->my_compproto = (PROTO_VJCOMP << 16) +
286503a7782SBrian Somers                          ((ipcp->cfg.VJInitSlots - 1) << 8) +
287503a7782SBrian Somers                          ipcp->cfg.VJInitComp;
2881ae349f5Scvs2svn   else
289503a7782SBrian Somers     ipcp->my_compproto = 0;
290eaa4df37SBrian Somers   sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.VJInitSlots - 1);
29129e275ceSBrian Somers 
292503a7782SBrian Somers   ipcp->peer_reject = 0;
293503a7782SBrian Somers   ipcp->my_reject = 0;
294503a7782SBrian Somers 
295503a7782SBrian Somers   throughput_init(&ipcp->throughput);
2961ae349f5Scvs2svn }
2971ae349f5Scvs2svn 
298455aabc3SBrian Somers static int
29930c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
30030c2f2ffSBrian Somers                   struct in_addr hisaddr, int silent)
301455aabc3SBrian Somers {
302455aabc3SBrian Somers   struct sockaddr_in *sock_in;
303455aabc3SBrian Somers   int s;
304455aabc3SBrian Somers   u_long mask, addr;
305455aabc3SBrian Somers   struct ifaliasreq ifra;
306455aabc3SBrian Somers 
307455aabc3SBrian Somers   /* If given addresses are alreay set, then ignore this request */
30830c2f2ffSBrian Somers   if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr &&
30930c2f2ffSBrian Somers       bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr)
310455aabc3SBrian Somers     return 0;
311455aabc3SBrian Somers 
31230c2f2ffSBrian Somers   IpcpCleanInterface(&bundle->ncp.ipcp.fsm);
31368a0f0ccSBrian Somers 
314455aabc3SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
315455aabc3SBrian Somers   if (s < 0) {
316455aabc3SBrian Somers     LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
317455aabc3SBrian Somers     return (-1);
318455aabc3SBrian Somers   }
319455aabc3SBrian Somers 
320455aabc3SBrian Somers   memset(&ifra, '\0', sizeof ifra);
321455aabc3SBrian Somers   strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1);
322455aabc3SBrian Somers   ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
323455aabc3SBrian Somers 
324455aabc3SBrian Somers   /* Set interface address */
325455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
326455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
327455aabc3SBrian Somers   sock_in->sin_addr = myaddr;
328455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
329455aabc3SBrian Somers 
330455aabc3SBrian Somers   /* Set destination address */
331455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
332455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
333455aabc3SBrian Somers   sock_in->sin_addr = hisaddr;
334455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
335455aabc3SBrian Somers 
336455aabc3SBrian Somers   addr = ntohl(myaddr.s_addr);
337455aabc3SBrian Somers   if (IN_CLASSA(addr))
338455aabc3SBrian Somers     mask = IN_CLASSA_NET;
339455aabc3SBrian Somers   else if (IN_CLASSB(addr))
340455aabc3SBrian Somers     mask = IN_CLASSB_NET;
341455aabc3SBrian Somers   else
342455aabc3SBrian Somers     mask = IN_CLASSC_NET;
343455aabc3SBrian Somers 
344455aabc3SBrian Somers   /* if subnet mask is given, use it instead of class mask */
34530c2f2ffSBrian Somers   if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY &&
34630c2f2ffSBrian Somers       (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask)
34730c2f2ffSBrian Somers     mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr);
348455aabc3SBrian Somers 
349455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
350455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
351455aabc3SBrian Somers   sock_in->sin_addr.s_addr = htonl(mask);
352455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
353455aabc3SBrian Somers 
354455aabc3SBrian Somers   if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
355455aabc3SBrian Somers     if (!silent)
356455aabc3SBrian Somers       LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n",
357455aabc3SBrian Somers 		strerror(errno));
358455aabc3SBrian Somers     close(s);
359455aabc3SBrian Somers     return (-1);
360455aabc3SBrian Somers   }
361455aabc3SBrian Somers 
36230c2f2ffSBrian Somers   bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr;
36330c2f2ffSBrian Somers   bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr;
364455aabc3SBrian Somers 
365455aabc3SBrian Somers   if (Enabled(ConfProxy))
36630c2f2ffSBrian Somers     sifproxyarp(bundle, bundle->ncp.ipcp.peer_ifip, s);
367455aabc3SBrian Somers 
368455aabc3SBrian Somers   close(s);
369455aabc3SBrian Somers   return (0);
370455aabc3SBrian Somers }
371455aabc3SBrian Somers 
372455aabc3SBrian Somers static struct in_addr
37330c2f2ffSBrian Somers ChooseHisAddr(struct bundle *bundle, const struct in_addr gw)
374455aabc3SBrian Somers {
375455aabc3SBrian Somers   struct in_addr try;
376455aabc3SBrian Somers   int f;
377455aabc3SBrian Somers 
3785828db6dSBrian Somers   for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
3795828db6dSBrian Somers     try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
380455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
381455aabc3SBrian Somers               f, inet_ntoa(try));
38230c2f2ffSBrian Somers     if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
383455aabc3SBrian Somers       LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
384455aabc3SBrian Somers                 inet_ntoa(try));
385455aabc3SBrian Somers       break;
386455aabc3SBrian Somers     }
387455aabc3SBrian Somers   }
388455aabc3SBrian Somers 
3895828db6dSBrian Somers   if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
390455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
391455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
392455aabc3SBrian Somers   }
393455aabc3SBrian Somers 
394455aabc3SBrian Somers   return try;
395455aabc3SBrian Somers }
396455aabc3SBrian Somers 
3971ae349f5Scvs2svn static void
3981ae349f5Scvs2svn IpcpInitRestartCounter(struct fsm * fp)
3991ae349f5Scvs2svn {
4007308ec68SBrian Somers   /* Set fsm timer load */
4011ae349f5Scvs2svn   fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
4021ae349f5Scvs2svn   fp->restart = 5;
4031ae349f5Scvs2svn }
4041ae349f5Scvs2svn 
4051ae349f5Scvs2svn static void
4061ae349f5Scvs2svn IpcpSendConfigReq(struct fsm *fp)
4071ae349f5Scvs2svn {
4087308ec68SBrian Somers   /* Send config REQ please */
4098c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
410aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
4112267893fSBrian Somers   u_char buff[12];
4122267893fSBrian Somers   struct lcp_opt *o;
4131ae349f5Scvs2svn 
4142267893fSBrian Somers   o = (struct lcp_opt *)buff;
41530c2f2ffSBrian Somers 
41683d1af55SBrian Somers   if ((p && !Physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
4172267893fSBrian Somers     *(u_int32_t *)o->data = ipcp->my_ip.s_addr;
4182267893fSBrian Somers     INC_LCP_OPT(TY_IPADDR, 6, o);
4191ae349f5Scvs2svn   }
4201ae349f5Scvs2svn 
4212267893fSBrian Somers   if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO))
42283d1af55SBrian Somers     if (ipcp->heis1172) {
4232267893fSBrian Somers       *(u_short *)o->data = htons(PROTO_VJCOMP);
4242267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 4, o);
4251ae349f5Scvs2svn     } else {
4262267893fSBrian Somers       *(u_long *)o->data = htonl(ipcp->my_compproto);
4272267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 6, o);
4281ae349f5Scvs2svn     }
4292267893fSBrian Somers 
4302267893fSBrian Somers   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
4311ae349f5Scvs2svn }
4321ae349f5Scvs2svn 
4331ae349f5Scvs2svn static void
4342267893fSBrian Somers IpcpSentTerminateReq(struct fsm * fp)
4351ae349f5Scvs2svn {
4367308ec68SBrian Somers   /* Term REQ just sent by FSM */
4371ae349f5Scvs2svn }
4381ae349f5Scvs2svn 
4391ae349f5Scvs2svn static void
4402267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id)
4411ae349f5Scvs2svn {
4427308ec68SBrian Somers   /* Send Term ACK please */
4432267893fSBrian Somers   FsmOutput(fp, CODE_TERMACK, id, NULL, 0);
4441ae349f5Scvs2svn }
4451ae349f5Scvs2svn 
4461ae349f5Scvs2svn static void
4471ae349f5Scvs2svn IpcpLayerStart(struct fsm * fp)
4481ae349f5Scvs2svn {
4497308ec68SBrian Somers   /* We're about to start up ! */
4501ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerStart.\n");
451455aabc3SBrian Somers 
452455aabc3SBrian Somers   /* This is where we should be setting up the interface in AUTO mode */
4531ae349f5Scvs2svn }
4541ae349f5Scvs2svn 
4551ae349f5Scvs2svn static void
4561ae349f5Scvs2svn IpcpLayerFinish(struct fsm *fp)
4571ae349f5Scvs2svn {
4587308ec68SBrian Somers   /* We're now down */
4591ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerFinish.\n");
4601ae349f5Scvs2svn }
4611ae349f5Scvs2svn 
46268a0f0ccSBrian Somers void
46368a0f0ccSBrian Somers IpcpCleanInterface(struct fsm *fp)
46468a0f0ccSBrian Somers {
46568a0f0ccSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
46668a0f0ccSBrian Somers   struct ifaliasreq ifra;
46768a0f0ccSBrian Somers   struct sockaddr_in *me, *peer;
46868a0f0ccSBrian Somers   int s;
46968a0f0ccSBrian Somers 
47068a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
47168a0f0ccSBrian Somers   if (s < 0) {
47268a0f0ccSBrian Somers     LogPrintf(LogERROR, "IpcpCleanInterface: socket: %s\n", strerror(errno));
47368a0f0ccSBrian Somers     return;
47468a0f0ccSBrian Somers   }
47568a0f0ccSBrian Somers 
47668a0f0ccSBrian Somers   if (Enabled(ConfProxy))
477503a7782SBrian Somers     cifproxyarp(fp->bundle, ipcp->peer_ifip, s);
47868a0f0ccSBrian Somers 
479503a7782SBrian Somers   if (ipcp->my_ifip.s_addr != INADDR_ANY ||
480503a7782SBrian Somers       ipcp->peer_ifip.s_addr != INADDR_ANY) {
48168a0f0ccSBrian Somers     memset(&ifra, '\0', sizeof ifra);
48268a0f0ccSBrian Somers     strncpy(ifra.ifra_name, fp->bundle->ifname, sizeof ifra.ifra_name - 1);
48368a0f0ccSBrian Somers     ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
48468a0f0ccSBrian Somers     me = (struct sockaddr_in *)&ifra.ifra_addr;
48568a0f0ccSBrian Somers     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
48668a0f0ccSBrian Somers     me->sin_family = peer->sin_family = AF_INET;
48768a0f0ccSBrian Somers     me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
488503a7782SBrian Somers     me->sin_addr = ipcp->my_ifip;
489503a7782SBrian Somers     peer->sin_addr = ipcp->peer_ifip;
49068a0f0ccSBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
49168a0f0ccSBrian Somers       LogPrintf(LogERROR, "IpcpCleanInterface: ioctl(SIOCDIFADDR): %s\n",
49268a0f0ccSBrian Somers                 strerror(errno));
49368a0f0ccSBrian Somers       close(s);
49468a0f0ccSBrian Somers     }
495503a7782SBrian Somers     ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY;
49668a0f0ccSBrian Somers   }
49768a0f0ccSBrian Somers 
49868a0f0ccSBrian Somers   close(s);
49968a0f0ccSBrian Somers }
50068a0f0ccSBrian Somers 
5011ae349f5Scvs2svn static void
5021ae349f5Scvs2svn IpcpLayerDown(struct fsm *fp)
5031ae349f5Scvs2svn {
5047308ec68SBrian Somers   /* About to come down */
505aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
506455aabc3SBrian Somers   const char *s;
507455aabc3SBrian Somers 
508503a7782SBrian Somers   s = inet_ntoa(ipcp->peer_ifip);
509455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerDown: %s\n", s);
510455aabc3SBrian Somers 
51183d1af55SBrian Somers   throughput_stop(&ipcp->throughput);
51283d1af55SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
513455aabc3SBrian Somers   /*
514455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
515455aabc3SBrian Somers    * associate executable sections in files with events.
516455aabc3SBrian Somers    */
517455aabc3SBrian Somers   if (SelectSystem(fp->bundle, s, LINKDOWNFILE) < 0)
518455aabc3SBrian Somers     if (GetLabel()) {
519455aabc3SBrian Somers        if (SelectSystem(fp->bundle, GetLabel(), LINKDOWNFILE) < 0)
520455aabc3SBrian Somers        SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE);
521455aabc3SBrian Somers     } else
522455aabc3SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE);
523455aabc3SBrian Somers 
52468a0f0ccSBrian Somers   if (!(mode & MODE_AUTO))
52568a0f0ccSBrian Somers     IpcpCleanInterface(fp);
5261ae349f5Scvs2svn }
5271ae349f5Scvs2svn 
5281ae349f5Scvs2svn static void
5291ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp)
5301ae349f5Scvs2svn {
5317308ec68SBrian Somers   /* We're now up */
532aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
5331ae349f5Scvs2svn   char tbuff[100];
5341ae349f5Scvs2svn 
5352267893fSBrian Somers   LogPrintf(LogIPCP, "IpcpLayerUp.\n");
536503a7782SBrian Somers   snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
537455aabc3SBrian Somers   LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n",
538503a7782SBrian Somers 	    tbuff, inet_ntoa(ipcp->peer_ip));
5391ae349f5Scvs2svn 
540503a7782SBrian Somers   if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
541eaa4df37SBrian Somers     sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
5421ae349f5Scvs2svn 
54330c2f2ffSBrian Somers   if (ipcp_SetIPaddress(fp->bundle, ipcp->my_ip,
54430c2f2ffSBrian Somers                         ipcp->peer_ip, 0) < 0) {
5451ae349f5Scvs2svn     LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
5461ae349f5Scvs2svn     return;
5471ae349f5Scvs2svn   }
548455aabc3SBrian Somers 
5491ae349f5Scvs2svn #ifndef NOALIAS
5501ae349f5Scvs2svn   if (mode & MODE_ALIAS)
551503a7782SBrian Somers     VarPacketAliasSetAddress(ipcp->my_ip);
5521ae349f5Scvs2svn #endif
553455aabc3SBrian Somers 
554455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerUp: %s\n",
555503a7782SBrian Somers             inet_ntoa(ipcp->peer_ifip));
556455aabc3SBrian Somers 
557455aabc3SBrian Somers   /*
558455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
559455aabc3SBrian Somers    * associate executable sections in files with events.
560455aabc3SBrian Somers    */
561503a7782SBrian Somers   if (SelectSystem(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE) < 0)
562455aabc3SBrian Somers     if (GetLabel()) {
563455aabc3SBrian Somers       if (SelectSystem(fp->bundle, GetLabel(), LINKUPFILE) < 0)
564455aabc3SBrian Somers         SelectSystem(fp->bundle, "MYADDR", LINKUPFILE);
565455aabc3SBrian Somers     } else
566455aabc3SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKUPFILE);
567455aabc3SBrian Somers 
5683b0f8d2eSBrian Somers   throughput_start(&ipcp->throughput, "IPCP throughput");
56985b542cfSBrian Somers   prompt_Display(&prompt, fp->bundle);
5701ae349f5Scvs2svn }
5711ae349f5Scvs2svn 
5721ae349f5Scvs2svn static int
5731ae349f5Scvs2svn AcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
5741ae349f5Scvs2svn {
5757308ec68SBrian Somers   /* Is the given IP in the given range ? */
5761ae349f5Scvs2svn   LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr));
5771ae349f5Scvs2svn   LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr));
5781ae349f5Scvs2svn   LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr));
5791ae349f5Scvs2svn   LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange->
5801ae349f5Scvs2svn 		  mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr));
5811ae349f5Scvs2svn   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
5821ae349f5Scvs2svn     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
5831ae349f5Scvs2svn }
5841ae349f5Scvs2svn 
5851ae349f5Scvs2svn static void
58630c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
58730c2f2ffSBrian Somers                  struct fsm_decode *dec)
5881ae349f5Scvs2svn {
5897308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
590aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
5911ae349f5Scvs2svn   int type, length;
5921ae349f5Scvs2svn   u_long *lp, compproto;
5931ae349f5Scvs2svn   struct compreq *pcomp;
5941ae349f5Scvs2svn   struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
59530c2f2ffSBrian Somers   char tbuff[100], tbuff2[100];
5961ae349f5Scvs2svn 
5971ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
5981ae349f5Scvs2svn     type = *cp;
5991ae349f5Scvs2svn     length = cp[1];
6001ae349f5Scvs2svn     if (type < NCFTYPES)
6011ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
6021ae349f5Scvs2svn     else if (type > 128 && type < 128 + NCFTYPES128)
6031ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
6041ae349f5Scvs2svn     else
6051ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
6061ae349f5Scvs2svn 
6071ae349f5Scvs2svn     switch (type) {
6081ae349f5Scvs2svn     case TY_IPADDR:		/* RFC1332 */
6091ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6101ae349f5Scvs2svn       ipaddr.s_addr = *lp;
6111ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
6121ae349f5Scvs2svn 
6131ae349f5Scvs2svn       switch (mode_type) {
6141ae349f5Scvs2svn       case MODE_REQ:
615503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
6161ae349f5Scvs2svn           if (ipaddr.s_addr == INADDR_ANY ||
617503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
61830c2f2ffSBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
61930c2f2ffSBrian Somers                                 ipaddr, 1)) {
6201ae349f5Scvs2svn             LogPrintf(LogIPCP, "%s: Address invalid or already in use\n",
6211ae349f5Scvs2svn                       inet_ntoa(ipaddr));
622503a7782SBrian Somers             ipcp->peer_ip = ChooseHisAddr
62330c2f2ffSBrian Somers               (fp->bundle, ipcp->cfg.my_range.ipaddr);
624503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
62530c2f2ffSBrian Somers 	      memcpy(dec->rejend, cp, length);
62630c2f2ffSBrian Somers 	      dec->rejend += length;
6271ae349f5Scvs2svn             } else {
62830c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
62930c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
63030c2f2ffSBrian Somers 	      dec->nakend += length;
6311ae349f5Scvs2svn             }
6321ae349f5Scvs2svn 	    break;
6331ae349f5Scvs2svn           }
634503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
6351ae349f5Scvs2svn 	  /*
6361ae349f5Scvs2svn 	   * If destination address is not acceptable, insist to use what we
6371ae349f5Scvs2svn 	   * want to use.
6381ae349f5Scvs2svn 	   */
63930c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
64030c2f2ffSBrian Somers 	  memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
64130c2f2ffSBrian Somers 	  dec->nakend += length;
6421ae349f5Scvs2svn 	  break;
6431ae349f5Scvs2svn 	}
644503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
64530c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
64630c2f2ffSBrian Somers 	dec->ackend += length;
6471ae349f5Scvs2svn 	break;
6481ae349f5Scvs2svn       case MODE_NAK:
649503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
6501ae349f5Scvs2svn 	  /* Use address suggested by peer */
6511ae349f5Scvs2svn 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
652503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
6531ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
654503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
6551ae349f5Scvs2svn 	} else {
6561ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
65783d1af55SBrian Somers           FsmClose(&ipcp->fsm);
6581ae349f5Scvs2svn 	}
6591ae349f5Scvs2svn 	break;
6601ae349f5Scvs2svn       case MODE_REJ:
661503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
6621ae349f5Scvs2svn 	break;
6631ae349f5Scvs2svn       }
6641ae349f5Scvs2svn       break;
6651ae349f5Scvs2svn     case TY_COMPPROTO:
6661ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6671ae349f5Scvs2svn       compproto = htonl(*lp);
6681ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
6691ae349f5Scvs2svn 
6701ae349f5Scvs2svn       switch (mode_type) {
6711ae349f5Scvs2svn       case MODE_REQ:
6721ae349f5Scvs2svn 	if (!Acceptable(ConfVjcomp)) {
67330c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
67430c2f2ffSBrian Somers 	  dec->rejend += length;
6751ae349f5Scvs2svn 	} else {
6761ae349f5Scvs2svn 	  pcomp = (struct compreq *) (cp + 2);
6771ae349f5Scvs2svn 	  switch (length) {
6781ae349f5Scvs2svn 	  case 4:		/* RFC1172 */
6791ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
6801ae349f5Scvs2svn 	      LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
68183d1af55SBrian Somers 	      ipcp->heis1172 = 1;
682503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
68330c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
68430c2f2ffSBrian Somers 	      dec->ackend += length;
6851ae349f5Scvs2svn 	    } else {
68630c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
6871ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
68830c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, 2);
68930c2f2ffSBrian Somers 	      dec->nakend += length;
6901ae349f5Scvs2svn 	    }
6911ae349f5Scvs2svn 	    break;
6921ae349f5Scvs2svn 	  case 6:		/* RFC1332 */
6931ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
694503a7782SBrian Somers 		&& pcomp->slots <= MAX_VJ_STATES
695503a7782SBrian Somers                 && pcomp->slots >= MIN_VJ_STATES) {
696503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
69783d1af55SBrian Somers 	      ipcp->heis1172 = 0;
69830c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
69930c2f2ffSBrian Somers 	      dec->ackend += length;
7001ae349f5Scvs2svn 	    } else {
70130c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
7021ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
703503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
7041ae349f5Scvs2svn 	      pcomp->compcid = 0;
70530c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
70630c2f2ffSBrian Somers 	      dec->nakend += length;
7071ae349f5Scvs2svn 	    }
7081ae349f5Scvs2svn 	    break;
7091ae349f5Scvs2svn 	  default:
71030c2f2ffSBrian Somers 	    memcpy(dec->rejend, cp, length);
71130c2f2ffSBrian Somers 	    dec->rejend += length;
7121ae349f5Scvs2svn 	    break;
7131ae349f5Scvs2svn 	  }
7141ae349f5Scvs2svn 	}
7151ae349f5Scvs2svn 	break;
7161ae349f5Scvs2svn       case MODE_NAK:
7171ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
718503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
719503a7782SBrian Somers 	ipcp->my_compproto = compproto;
7201ae349f5Scvs2svn 	break;
7211ae349f5Scvs2svn       case MODE_REJ:
722503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
7231ae349f5Scvs2svn 	break;
7241ae349f5Scvs2svn       }
7251ae349f5Scvs2svn       break;
7261ae349f5Scvs2svn     case TY_IPADDRS:		/* RFC1172 */
7271ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
7281ae349f5Scvs2svn       ipaddr.s_addr = *lp;
7291ae349f5Scvs2svn       lp = (u_long *) (cp + 6);
7301ae349f5Scvs2svn       dstipaddr.s_addr = *lp;
7311ae349f5Scvs2svn       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
7321ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
7331ae349f5Scvs2svn 
7341ae349f5Scvs2svn       switch (mode_type) {
7351ae349f5Scvs2svn       case MODE_REQ:
736503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
737503a7782SBrian Somers 	ipcp->my_ip = dstipaddr;
73830c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
73930c2f2ffSBrian Somers 	dec->ackend += length;
7401ae349f5Scvs2svn 	break;
7411ae349f5Scvs2svn       case MODE_NAK:
7421ae349f5Scvs2svn         snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
743503a7782SBrian Somers 		 inet_ntoa(ipcp->my_ip));
7441ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
745503a7782SBrian Somers 	ipcp->my_ip = ipaddr;
746503a7782SBrian Somers 	ipcp->peer_ip = dstipaddr;
7471ae349f5Scvs2svn 	break;
7481ae349f5Scvs2svn       case MODE_REJ:
749503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
7501ae349f5Scvs2svn 	break;
7511ae349f5Scvs2svn       }
7521ae349f5Scvs2svn       break;
7531ae349f5Scvs2svn 
7541ae349f5Scvs2svn       /*
7551ae349f5Scvs2svn        * MS extensions for MS's PPP
7561ae349f5Scvs2svn        */
7571ae349f5Scvs2svn 
7581ae349f5Scvs2svn #ifndef NOMSEXT
7591ae349f5Scvs2svn     case TY_PRIMARY_DNS:	/* MS PPP DNS negotiation hack */
7601ae349f5Scvs2svn     case TY_SECONDARY_DNS:
76130c2f2ffSBrian Somers       switch (mode_type) {
76230c2f2ffSBrian Somers       case MODE_REQ:
7631ae349f5Scvs2svn         if (!Enabled(ConfMSExt)) {
7641ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n");
76583d1af55SBrian Somers 	  ipcp->my_reject |= (1 << type);
76630c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
76730c2f2ffSBrian Somers 	  dec->rejend += length;
7681ae349f5Scvs2svn 	  break;
7691ae349f5Scvs2svn         }
7701ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
7711ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
772503a7782SBrian Somers 	ms_info_req.s_addr = ipcp->cfg.ns_entries
77329e275ceSBrian Somers           [(type - TY_PRIMARY_DNS) ? 1 : 0].s_addr;
7741ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
7751ae349f5Scvs2svn 
7761ae349f5Scvs2svn 	  /*
7771ae349f5Scvs2svn 	   * So the client has got the DNS stuff wrong (first request) so
7781ae349f5Scvs2svn 	   * we'll tell 'em how it is
7791ae349f5Scvs2svn 	   */
78030c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
7811ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n",
7822267893fSBrian Somers 		    type, inet_ntoa(dnsstuff), inet_ntoa(ms_info_req));
78330c2f2ffSBrian Somers 	  memcpy(dec->nakend+2, &ms_info_req, length);
78430c2f2ffSBrian Somers 	  dec->nakend += length;
7851ae349f5Scvs2svn 	  break;
7861ae349f5Scvs2svn 	}
7871ae349f5Scvs2svn 
7881ae349f5Scvs2svn 	/*
7891ae349f5Scvs2svn 	 * Otherwise they have it right (this time) so we send a ack packet
7901ae349f5Scvs2svn 	 * back confirming it... end of story
7911ae349f5Scvs2svn 	 */
7921ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n",
7932267893fSBrian Somers 		  type, inet_ntoa(ms_info_req));
79430c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
79530c2f2ffSBrian Somers 	dec->ackend += length;
7961ae349f5Scvs2svn 	break;
7971ae349f5Scvs2svn       case MODE_NAK:		/* what does this mean?? */
7981ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type);
7991ae349f5Scvs2svn 	break;
8001ae349f5Scvs2svn       case MODE_REJ:		/* confused?? me to :) */
8011ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type);
8021ae349f5Scvs2svn 	break;
8031ae349f5Scvs2svn       }
8041ae349f5Scvs2svn       break;
8051ae349f5Scvs2svn 
8061ae349f5Scvs2svn     case TY_PRIMARY_NBNS:	/* MS PPP NetBIOS nameserver hack */
8071ae349f5Scvs2svn     case TY_SECONDARY_NBNS:
80830c2f2ffSBrian Somers       switch (mode_type) {
80930c2f2ffSBrian Somers       case MODE_REQ:
8101ae349f5Scvs2svn         if (!Enabled(ConfMSExt)) {
8111ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n");
81283d1af55SBrian Somers 	  ipcp->my_reject |= (1 << type);
81330c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
81430c2f2ffSBrian Somers 	  dec->rejend += length;
8151ae349f5Scvs2svn 	  break;
8161ae349f5Scvs2svn         }
8171ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
8181ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
819503a7782SBrian Somers 	ms_info_req.s_addr = ipcp->cfg.nbns_entries
82029e275ceSBrian Somers           [(type - TY_PRIMARY_NBNS) ? 1 : 0].s_addr;
8211ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
82230c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
82330c2f2ffSBrian Somers 	  memcpy(dec->nakend+2, &ms_info_req.s_addr, length);
8241ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n",
8252267893fSBrian Somers 		    type, inet_ntoa(dnsstuff), inet_ntoa(ms_info_req));
82630c2f2ffSBrian Somers 	  dec->nakend += length;
8271ae349f5Scvs2svn 	  break;
8281ae349f5Scvs2svn 	}
8291ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n",
8302267893fSBrian Somers 		  type, inet_ntoa(ms_info_req));
83130c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
83230c2f2ffSBrian Somers 	dec->ackend += length;
8331ae349f5Scvs2svn 	break;
8341ae349f5Scvs2svn       case MODE_NAK:
8351ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
8361ae349f5Scvs2svn 	break;
8371ae349f5Scvs2svn       case MODE_REJ:
8381ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
8391ae349f5Scvs2svn 	break;
8401ae349f5Scvs2svn       }
8411ae349f5Scvs2svn       break;
8421ae349f5Scvs2svn 
8431ae349f5Scvs2svn #endif
8441ae349f5Scvs2svn 
8451ae349f5Scvs2svn     default:
84630c2f2ffSBrian Somers       if (mode_type != MODE_NOP) {
84783d1af55SBrian Somers         ipcp->my_reject |= (1 << type);
84830c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
84930c2f2ffSBrian Somers         dec->rejend += length;
85030c2f2ffSBrian Somers       }
8511ae349f5Scvs2svn       break;
8521ae349f5Scvs2svn     }
8531ae349f5Scvs2svn     plen -= length;
8541ae349f5Scvs2svn     cp += length;
8551ae349f5Scvs2svn   }
8561ae349f5Scvs2svn }
8571ae349f5Scvs2svn 
8581ae349f5Scvs2svn void
8595828db6dSBrian Somers IpcpInput(struct ipcp *ipcp, struct mbuf * bp)
8601ae349f5Scvs2svn {
8617308ec68SBrian Somers   /* Got PROTO_IPCP from link */
8625828db6dSBrian Somers   FsmInput(&ipcp->fsm, bp);
8631ae349f5Scvs2svn }
8641ae349f5Scvs2svn 
8651ae349f5Scvs2svn int
8667a6f8720SBrian Somers UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
8671ae349f5Scvs2svn {
8685828db6dSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
8695828db6dSBrian Somers 
8707308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
8715828db6dSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
8725828db6dSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
8731ae349f5Scvs2svn   if (strpbrk(hisaddr, ",-")) {
8745828db6dSBrian Somers     iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
8755828db6dSBrian Somers     if (iplist_isvalid(&ipcp->cfg.peer_list)) {
8765828db6dSBrian Somers       iplist_setrandpos(&ipcp->cfg.peer_list);
87730c2f2ffSBrian Somers       ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
8785828db6dSBrian Somers       if (ipcp->peer_ip.s_addr == INADDR_ANY) {
8795828db6dSBrian Somers         LogPrintf(LogWARN, "%s: None available !\n",
8805828db6dSBrian Somers                   ipcp->cfg.peer_list.src);
8811ae349f5Scvs2svn         return(0);
8821ae349f5Scvs2svn       }
8835828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
8845828db6dSBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
8855828db6dSBrian Somers       ipcp->cfg.peer_range.width = 32;
8861ae349f5Scvs2svn     } else {
8871ae349f5Scvs2svn       LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr);
8881ae349f5Scvs2svn       return 0;
8891ae349f5Scvs2svn     }
8905828db6dSBrian Somers   } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr,
8915828db6dSBrian Somers 		       &ipcp->cfg.peer_range.mask,
8925828db6dSBrian Somers                        &ipcp->cfg.peer_range.width) != 0) {
8935828db6dSBrian Somers     ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
8941ae349f5Scvs2svn 
89530c2f2ffSBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
89630c2f2ffSBrian Somers                                      ipcp->cfg.peer_range.ipaddr, 0) < 0) {
8975828db6dSBrian Somers       ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
8985828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
8991ae349f5Scvs2svn       return 0;
9001ae349f5Scvs2svn     }
9011ae349f5Scvs2svn   } else
9021ae349f5Scvs2svn     return 0;
9031ae349f5Scvs2svn 
9041ae349f5Scvs2svn   return 1;
9051ae349f5Scvs2svn }
906