xref: /freebsd/usr.sbin/ppp/ipcp.c (revision 503a7782d83ae95e68461f93e5c0d703bd7e04e0)
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  *
20503a7782SBrian Somers  * $Id: ipcp.c,v 1.50.2.14 1998/02/19 19:56:59 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  *	TODO:
231ae349f5Scvs2svn  *		o More RFC1772 backwoard compatibility
241ae349f5Scvs2svn  */
251ae349f5Scvs2svn #include <sys/param.h>
261ae349f5Scvs2svn #include <netinet/in_systm.h>
271ae349f5Scvs2svn #include <netinet/in.h>
281ae349f5Scvs2svn #include <netinet/ip.h>
291ae349f5Scvs2svn #include <arpa/inet.h>
301ae349f5Scvs2svn #include <sys/socket.h>
311ae349f5Scvs2svn #include <netdb.h>
32455aabc3SBrian Somers #include <sys/time.h>
33455aabc3SBrian Somers #include <net/if.h>
34455aabc3SBrian Somers #include <sys/sockio.h>
351ae349f5Scvs2svn 
361ae349f5Scvs2svn #include <stdio.h>
371ae349f5Scvs2svn #include <stdlib.h>
381ae349f5Scvs2svn #include <string.h>
39455aabc3SBrian Somers #include <sys/errno.h>
406140ba11SBrian Somers #include <termios.h>
411ae349f5Scvs2svn #include <unistd.h>
421ae349f5Scvs2svn 
431ae349f5Scvs2svn #include "command.h"
441ae349f5Scvs2svn #include "mbuf.h"
451ae349f5Scvs2svn #include "log.h"
461ae349f5Scvs2svn #include "defs.h"
471ae349f5Scvs2svn #include "timer.h"
481ae349f5Scvs2svn #include "fsm.h"
491ae349f5Scvs2svn #include "lcpproto.h"
501ae349f5Scvs2svn #include "lcp.h"
511ae349f5Scvs2svn #include "iplist.h"
5229e275ceSBrian Somers #include "throughput.h"
531ae349f5Scvs2svn #include "ipcp.h"
541ae349f5Scvs2svn #include "slcompress.h"
557a6f8720SBrian Somers #include "bundle.h"
561ae349f5Scvs2svn #include "loadalias.h"
571ae349f5Scvs2svn #include "vars.h"
581ae349f5Scvs2svn #include "vjcomp.h"
591ae349f5Scvs2svn #include "ip.h"
601ae349f5Scvs2svn #include "route.h"
611ae349f5Scvs2svn #include "filter.h"
628c07a7b2SBrian Somers #include "hdlc.h"
636140ba11SBrian Somers #include "async.h"
648c07a7b2SBrian Somers #include "link.h"
6542d4d396SBrian Somers #include "descriptor.h"
6663b73463SBrian Somers #include "physical.h"
67455aabc3SBrian Somers #include "id.h"
68455aabc3SBrian Somers #include "arp.h"
69455aabc3SBrian Somers #include "systems.h"
7085b542cfSBrian Somers #include "prompt.h"
711ae349f5Scvs2svn 
72503a7782SBrian Somers #undef REJECTED
73503a7782SBrian Somers #define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
74503a7782SBrian Somers 
7529e275ceSBrian Somers struct compreq {
7629e275ceSBrian Somers   u_short proto;
7729e275ceSBrian Somers   u_char slots;
7829e275ceSBrian Somers   u_char compcid;
7929e275ceSBrian Somers };
801ae349f5Scvs2svn 
811ae349f5Scvs2svn static void IpcpLayerUp(struct fsm *);
821ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *);
837308ec68SBrian Somers static void IpcpLayerStart(struct fsm *);
847308ec68SBrian Somers static void IpcpLayerFinish(struct fsm *);
851ae349f5Scvs2svn static void IpcpInitRestartCounter(struct fsm *);
867308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *);
877308ec68SBrian Somers static void IpcpSendTerminateReq(struct fsm *);
887308ec68SBrian Somers static void IpcpSendTerminateAck(struct fsm *);
8983d1af55SBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int);
9083d1af55SBrian Somers 
9183d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = {
9283d1af55SBrian Somers   IpcpLayerUp,
9383d1af55SBrian Somers   IpcpLayerDown,
9483d1af55SBrian Somers   IpcpLayerStart,
9583d1af55SBrian Somers   IpcpLayerFinish,
9683d1af55SBrian Somers   IpcpInitRestartCounter,
9783d1af55SBrian Somers   IpcpSendConfigReq,
9883d1af55SBrian Somers   IpcpSendTerminateReq,
9983d1af55SBrian Somers   IpcpSendTerminateAck,
10083d1af55SBrian Somers   IpcpDecodeConfig,
101503a7782SBrian Somers   NullRecvResetReq,
102503a7782SBrian Somers   NullRecvResetAck
10383d1af55SBrian Somers };
1041ae349f5Scvs2svn 
105503a7782SBrian Somers struct ipcp IpcpInfo;
1061ae349f5Scvs2svn 
1071ae349f5Scvs2svn static const char *cftypes[] = {
1081ae349f5Scvs2svn   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1091ae349f5Scvs2svn   "???",
1101ae349f5Scvs2svn   "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
1111ae349f5Scvs2svn   "COMPPROTO",	/* 2: IP-Compression-Protocol */
1121ae349f5Scvs2svn   "IPADDR",	/* 3: IP-Address */
1131ae349f5Scvs2svn };
1141ae349f5Scvs2svn 
1151ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1161ae349f5Scvs2svn 
1171ae349f5Scvs2svn static const char *cftypes128[] = {
1181ae349f5Scvs2svn   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1191ae349f5Scvs2svn   "???",
1201ae349f5Scvs2svn   "PRIDNS",	/* 129: Primary DNS Server Address */
1211ae349f5Scvs2svn   "PRINBNS",	/* 130: Primary NBNS Server Address */
1221ae349f5Scvs2svn   "SECDNS",	/* 131: Secondary DNS Server Address */
1231ae349f5Scvs2svn   "SECNBNS",	/* 132: Secondary NBNS Server Address */
1241ae349f5Scvs2svn };
1251ae349f5Scvs2svn 
1261ae349f5Scvs2svn #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
1271ae349f5Scvs2svn 
1281ae349f5Scvs2svn void
1291ae349f5Scvs2svn IpcpAddInOctets(int n)
1301ae349f5Scvs2svn {
13129e275ceSBrian Somers   throughput_addin(&IpcpInfo.throughput, n);
1321ae349f5Scvs2svn }
1331ae349f5Scvs2svn 
1341ae349f5Scvs2svn void
1351ae349f5Scvs2svn IpcpAddOutOctets(int n)
1361ae349f5Scvs2svn {
13729e275ceSBrian Somers   throughput_addout(&IpcpInfo.throughput, n);
1381ae349f5Scvs2svn }
1391ae349f5Scvs2svn 
1401ae349f5Scvs2svn int
1411ae349f5Scvs2svn ReportIpcpStatus(struct cmdargs const *arg)
1421ae349f5Scvs2svn {
14385b542cfSBrian Somers   prompt_Printf(&prompt, "%s [%s]\n", IpcpInfo.fsm.name,
1447308ec68SBrian Somers           StateNames[IpcpInfo.fsm.state]);
1457308ec68SBrian Somers   if (IpcpInfo.fsm.state == ST_OPENED) {
14685b542cfSBrian Somers     prompt_Printf(&prompt, " His side:               %s, %s\n",
147503a7782SBrian Somers 	    inet_ntoa(IpcpInfo.peer_ip), vj2asc(IpcpInfo.peer_compproto));
14885b542cfSBrian Somers     prompt_Printf(&prompt, " My side:                %s, %s\n",
149503a7782SBrian Somers 	    inet_ntoa(IpcpInfo.my_ip), vj2asc(IpcpInfo.my_compproto));
1501ae349f5Scvs2svn   }
1511ae349f5Scvs2svn 
15285b542cfSBrian Somers   prompt_Printf(&prompt, "\nDefaults:\n");
15385b542cfSBrian Somers   prompt_Printf(&prompt, " My Address:             %s/%d\n",
154503a7782SBrian Somers 	  inet_ntoa(IpcpInfo.cfg.my_range.ipaddr), IpcpInfo.cfg.my_range.width);
155503a7782SBrian Somers   if (iplist_isvalid(&IpcpInfo.cfg.peer_list))
15685b542cfSBrian Somers     prompt_Printf(&prompt, " His Address:            %s\n",
157503a7782SBrian Somers             IpcpInfo.cfg.peer_list.src);
1581ae349f5Scvs2svn   else
15985b542cfSBrian Somers     prompt_Printf(&prompt, " His Address:            %s/%d\n",
160503a7782SBrian Somers 	  inet_ntoa(IpcpInfo.cfg.peer_range.ipaddr),
161503a7782SBrian Somers           IpcpInfo.cfg.peer_range.width);
162503a7782SBrian Somers   if (IpcpInfo.cfg.HaveTriggerAddress)
16385b542cfSBrian Somers     prompt_Printf(&prompt, " Negotiation(trigger):   %s\n",
164503a7782SBrian Somers             inet_ntoa(IpcpInfo.cfg.TriggerAddress));
1651ae349f5Scvs2svn   else
16685b542cfSBrian Somers     prompt_Printf(&prompt, " Negotiation(trigger):   MYADDR\n");
167503a7782SBrian Somers   prompt_Printf(&prompt, " Initial VJ slots:       %d\n",
168503a7782SBrian Somers                 IpcpInfo.cfg.VJInitSlots);
16985b542cfSBrian Somers   prompt_Printf(&prompt, " Initial VJ compression: %s\n",
170503a7782SBrian Somers           IpcpInfo.cfg.VJInitComp ? "on" : "off");
1711ae349f5Scvs2svn 
17285b542cfSBrian Somers   prompt_Printf(&prompt, "\n");
17385b542cfSBrian Somers   throughput_disp(&IpcpInfo.throughput);
1741ae349f5Scvs2svn 
1751ae349f5Scvs2svn   return 0;
1761ae349f5Scvs2svn }
1771ae349f5Scvs2svn 
1781ae349f5Scvs2svn int
1791ae349f5Scvs2svn SetInitVJ(struct cmdargs const *args)
1801ae349f5Scvs2svn {
1811ae349f5Scvs2svn   if (args->argc != 2)
1821ae349f5Scvs2svn     return -1;
1831ae349f5Scvs2svn   if (!strcasecmp(args->argv[0], "slots")) {
1841ae349f5Scvs2svn     int slots;
1851ae349f5Scvs2svn 
1861ae349f5Scvs2svn     slots = atoi(args->argv[1]);
1871ae349f5Scvs2svn     if (slots < 4 || slots > 16)
1881ae349f5Scvs2svn       return 1;
189503a7782SBrian Somers     IpcpInfo.cfg.VJInitSlots = slots;
1901ae349f5Scvs2svn     return 0;
1911ae349f5Scvs2svn   } else if (!strcasecmp(args->argv[0], "slotcomp")) {
1921ae349f5Scvs2svn     if (!strcasecmp(args->argv[1], "on"))
193503a7782SBrian Somers       IpcpInfo.cfg.VJInitComp = 1;
1941ae349f5Scvs2svn     else if (!strcasecmp(args->argv[1], "off"))
195503a7782SBrian Somers       IpcpInfo.cfg.VJInitComp = 0;
1961ae349f5Scvs2svn     else
1971ae349f5Scvs2svn       return 2;
1981ae349f5Scvs2svn     return 0;
1991ae349f5Scvs2svn   }
2001ae349f5Scvs2svn   return -1;
2011ae349f5Scvs2svn }
2021ae349f5Scvs2svn 
2031ae349f5Scvs2svn void
204503a7782SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l)
2051ae349f5Scvs2svn {
206503a7782SBrian Somers   struct hostent *hp;
207503a7782SBrian Somers   char name[MAXHOSTNAMELEN];
20829e275ceSBrian Somers 
209503a7782SBrian Somers   fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, IPCP_MAXCODE, 10, LogIPCP,
210503a7782SBrian Somers            bundle, l, &ipcp_Callbacks);
211503a7782SBrian Somers 
212503a7782SBrian Somers   ipcp->cfg.VJInitSlots = DEF_VJ_STATES;
213503a7782SBrian Somers   ipcp->cfg.VJInitComp = 1;
214503a7782SBrian Somers   memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
215503a7782SBrian Somers   if (gethostname(name, sizeof name) == 0) {
216503a7782SBrian Somers     hp = gethostbyname(name);
217503a7782SBrian Somers     if (hp && hp->h_addrtype == AF_INET) {
218503a7782SBrian Somers       memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
219503a7782SBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
220503a7782SBrian Somers       ipcp->cfg.peer_range.width = 32;
2211ae349f5Scvs2svn     }
222503a7782SBrian Somers   }
223503a7782SBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
224503a7782SBrian Somers   iplist_setsrc(&ipcp->cfg.peer_list, "");
225503a7782SBrian Somers   ipcp->cfg.HaveTriggerAddress = 0;
226503a7782SBrian Somers 
227503a7782SBrian Somers   ipcp->cfg.ns_entries[0].s_addr = INADDR_ANY;
228503a7782SBrian Somers   ipcp->cfg.ns_entries[1].s_addr = INADDR_ANY;
229503a7782SBrian Somers   ipcp->cfg.nbns_entries[0].s_addr = INADDR_ANY;
230503a7782SBrian Somers   ipcp->cfg.nbns_entries[1].s_addr = INADDR_ANY;
231503a7782SBrian Somers 
232503a7782SBrian Somers   ipcp->my_ifip.s_addr = INADDR_ANY;
233503a7782SBrian Somers   ipcp->peer_ifip.s_addr = INADDR_ANY;
234503a7782SBrian Somers 
235503a7782SBrian Somers   ipcp_Setup(ipcp);
236503a7782SBrian Somers }
237503a7782SBrian Somers 
238503a7782SBrian Somers void
239503a7782SBrian Somers ipcp_Setup(struct ipcp *ipcp)
240503a7782SBrian Somers {
241503a7782SBrian Somers   int pos;
242503a7782SBrian Somers 
243503a7782SBrian Somers   ipcp->fsm.open_mode = 0;
244503a7782SBrian Somers 
245503a7782SBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list)) {
246503a7782SBrian Somers     if (ipcp->my_ifip.s_addr != INADDR_ANY &&
247503a7782SBrian Somers         (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1)
248503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos);
249503a7782SBrian Somers     else
250503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
251503a7782SBrian Somers     ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
252503a7782SBrian Somers     ipcp->cfg.peer_range.width = 32;
253503a7782SBrian Somers   }
254503a7782SBrian Somers 
255503a7782SBrian Somers   ipcp->heis1172 = 0;
256503a7782SBrian Somers 
257503a7782SBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
258503a7782SBrian Somers   ipcp->peer_compproto = 0;
2591ae349f5Scvs2svn 
2601ae349f5Scvs2svn   /*
2611ae349f5Scvs2svn    * Some implementations of PPP require that we send a
2621ae349f5Scvs2svn    * *special* value as our address, even though the rfc specifies
2631ae349f5Scvs2svn    * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
2641ae349f5Scvs2svn    */
265503a7782SBrian Somers   if (ipcp->cfg.HaveTriggerAddress) {
266503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.TriggerAddress;
26729e275ceSBrian Somers     LogPrintf(LogIPCP, "Using trigger address %s\n",
268503a7782SBrian Somers               inet_ntoa(ipcp->cfg.TriggerAddress));
269503a7782SBrian Somers   } else
270503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
27129e275ceSBrian Somers 
2721ae349f5Scvs2svn   if (Enabled(ConfVjcomp))
273503a7782SBrian Somers     ipcp->my_compproto = (PROTO_VJCOMP << 16) +
274503a7782SBrian Somers                          ((ipcp->cfg.VJInitSlots - 1) << 8) +
275503a7782SBrian Somers                          ipcp->cfg.VJInitComp;
2761ae349f5Scvs2svn   else
277503a7782SBrian Somers     ipcp->my_compproto = 0;
278503a7782SBrian Somers   VjInit(ipcp->cfg.VJInitSlots - 1);
27929e275ceSBrian Somers 
280503a7782SBrian Somers   ipcp->peer_reject = 0;
281503a7782SBrian Somers   ipcp->my_reject = 0;
282503a7782SBrian Somers 
283503a7782SBrian Somers   throughput_init(&ipcp->throughput);
2841ae349f5Scvs2svn }
2851ae349f5Scvs2svn 
286455aabc3SBrian Somers static int
287aad81d1eSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct ipcp *ipcp,
288455aabc3SBrian Somers                   struct in_addr myaddr, struct in_addr hisaddr,
289455aabc3SBrian Somers                   struct in_addr netmask, int silent)
290455aabc3SBrian Somers {
291455aabc3SBrian Somers   struct sockaddr_in *sock_in;
292455aabc3SBrian Somers   int s;
293455aabc3SBrian Somers   u_long mask, addr;
294455aabc3SBrian Somers   struct ifaliasreq ifra;
295455aabc3SBrian Somers 
296455aabc3SBrian Somers   /* If given addresses are alreay set, then ignore this request */
297503a7782SBrian Somers   if (ipcp->my_ifip.s_addr == myaddr.s_addr &&
298503a7782SBrian Somers       ipcp->peer_ifip.s_addr == hisaddr.s_addr)
299455aabc3SBrian Somers     return 0;
300455aabc3SBrian Somers 
30168a0f0ccSBrian Somers   IpcpCleanInterface(&ipcp->fsm);
30268a0f0ccSBrian Somers 
303455aabc3SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
304455aabc3SBrian Somers   if (s < 0) {
305455aabc3SBrian Somers     LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
306455aabc3SBrian Somers     return (-1);
307455aabc3SBrian Somers   }
308455aabc3SBrian Somers 
309455aabc3SBrian Somers   memset(&ifra, '\0', sizeof ifra);
310455aabc3SBrian Somers   strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1);
311455aabc3SBrian Somers   ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
312455aabc3SBrian Somers 
313455aabc3SBrian Somers   /* Set interface address */
314455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
315455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
316455aabc3SBrian Somers   sock_in->sin_addr = myaddr;
317455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
318455aabc3SBrian Somers 
319455aabc3SBrian Somers   /* Set destination address */
320455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
321455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
322455aabc3SBrian Somers   sock_in->sin_addr = hisaddr;
323455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
324455aabc3SBrian Somers 
325455aabc3SBrian Somers   addr = ntohl(myaddr.s_addr);
326455aabc3SBrian Somers   if (IN_CLASSA(addr))
327455aabc3SBrian Somers     mask = IN_CLASSA_NET;
328455aabc3SBrian Somers   else if (IN_CLASSB(addr))
329455aabc3SBrian Somers     mask = IN_CLASSB_NET;
330455aabc3SBrian Somers   else
331455aabc3SBrian Somers     mask = IN_CLASSC_NET;
332455aabc3SBrian Somers 
333455aabc3SBrian Somers   /* if subnet mask is given, use it instead of class mask */
334455aabc3SBrian Somers   if (netmask.s_addr != INADDR_ANY && (ntohl(netmask.s_addr) & mask) == mask)
335455aabc3SBrian Somers     mask = ntohl(netmask.s_addr);
336455aabc3SBrian Somers 
337455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
338455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
339455aabc3SBrian Somers   sock_in->sin_addr.s_addr = htonl(mask);
340455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
341455aabc3SBrian Somers 
342455aabc3SBrian Somers   if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
343455aabc3SBrian Somers     if (!silent)
344455aabc3SBrian Somers       LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n",
345455aabc3SBrian Somers 		strerror(errno));
346455aabc3SBrian Somers     close(s);
347455aabc3SBrian Somers     return (-1);
348455aabc3SBrian Somers   }
349455aabc3SBrian Somers 
350503a7782SBrian Somers   ipcp->peer_ifip.s_addr = hisaddr.s_addr;
351503a7782SBrian Somers   ipcp->my_ifip.s_addr = myaddr.s_addr;
352455aabc3SBrian Somers 
353455aabc3SBrian Somers   if (Enabled(ConfProxy))
354503a7782SBrian Somers     sifproxyarp(bundle, ipcp->peer_ifip, s);
355455aabc3SBrian Somers 
356455aabc3SBrian Somers   close(s);
357455aabc3SBrian Somers   return (0);
358455aabc3SBrian Somers }
359455aabc3SBrian Somers 
360455aabc3SBrian Somers static struct in_addr
361aad81d1eSBrian Somers ChooseHisAddr(struct bundle *bundle, struct ipcp *ipcp,
362455aabc3SBrian Somers               const struct in_addr gw)
363455aabc3SBrian Somers {
364455aabc3SBrian Somers   struct in_addr try;
365455aabc3SBrian Somers   int f;
366455aabc3SBrian Somers 
367503a7782SBrian Somers   for (f = 0; f < IpcpInfo.cfg.peer_list.nItems; f++) {
368503a7782SBrian Somers     try = iplist_next(&IpcpInfo.cfg.peer_list);
369455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
370455aabc3SBrian Somers               f, inet_ntoa(try));
371455aabc3SBrian Somers     if (ipcp_SetIPaddress(bundle, ipcp, gw, try, ifnetmask, 1) == 0) {
372455aabc3SBrian Somers       LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
373455aabc3SBrian Somers                 inet_ntoa(try));
374455aabc3SBrian Somers       break;
375455aabc3SBrian Somers     }
376455aabc3SBrian Somers   }
377455aabc3SBrian Somers 
378503a7782SBrian Somers   if (f == IpcpInfo.cfg.peer_list.nItems) {
379455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
380455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
381455aabc3SBrian Somers   }
382455aabc3SBrian Somers 
383455aabc3SBrian Somers   return try;
384455aabc3SBrian Somers }
385455aabc3SBrian Somers 
3861ae349f5Scvs2svn static void
3871ae349f5Scvs2svn IpcpInitRestartCounter(struct fsm * fp)
3881ae349f5Scvs2svn {
3897308ec68SBrian Somers   /* Set fsm timer load */
3901ae349f5Scvs2svn   fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
3911ae349f5Scvs2svn   fp->restart = 5;
3921ae349f5Scvs2svn }
3931ae349f5Scvs2svn 
3941ae349f5Scvs2svn static void
3951ae349f5Scvs2svn IpcpSendConfigReq(struct fsm *fp)
3961ae349f5Scvs2svn {
3977308ec68SBrian Somers   /* Send config REQ please */
3988c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
399aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
4001ae349f5Scvs2svn   u_char *cp;
4011ae349f5Scvs2svn   struct lcp_opt o;
4021ae349f5Scvs2svn 
4031ae349f5Scvs2svn   cp = ReqBuff;
4041ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpSendConfigReq\n");
40583d1af55SBrian Somers   if ((p && !Physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
4061ae349f5Scvs2svn     o.id = TY_IPADDR;
4071ae349f5Scvs2svn     o.len = 6;
408503a7782SBrian Somers     *(u_long *)o.data = ipcp->my_ip.s_addr;
4091ae349f5Scvs2svn     cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id],
410503a7782SBrian Somers                      inet_ntoa(ipcp->my_ip));
4111ae349f5Scvs2svn   }
4121ae349f5Scvs2svn 
413503a7782SBrian Somers   if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
4141ae349f5Scvs2svn     const char *args;
4151ae349f5Scvs2svn     o.id = TY_COMPPROTO;
41683d1af55SBrian Somers     if (ipcp->heis1172) {
4171ae349f5Scvs2svn       o.len = 4;
4181ae349f5Scvs2svn       *(u_short *)o.data = htons(PROTO_VJCOMP);
4191ae349f5Scvs2svn       args = "";
4201ae349f5Scvs2svn     } else {
4211ae349f5Scvs2svn       o.len = 6;
422503a7782SBrian Somers       *(u_long *)o.data = htonl(ipcp->my_compproto);
423503a7782SBrian Somers       args = vj2asc(ipcp->my_compproto);
4241ae349f5Scvs2svn     }
4251ae349f5Scvs2svn     cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], args);
4261ae349f5Scvs2svn   }
4271ae349f5Scvs2svn   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
4281ae349f5Scvs2svn }
4291ae349f5Scvs2svn 
4301ae349f5Scvs2svn static void
4311ae349f5Scvs2svn IpcpSendTerminateReq(struct fsm * fp)
4321ae349f5Scvs2svn {
4337308ec68SBrian Somers   /* Term REQ just sent by FSM */
4341ae349f5Scvs2svn }
4351ae349f5Scvs2svn 
4361ae349f5Scvs2svn static void
4371ae349f5Scvs2svn IpcpSendTerminateAck(struct fsm * fp)
4381ae349f5Scvs2svn {
4397308ec68SBrian Somers   /* Send Term ACK please */
4401ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpSendTerminateAck\n");
4411ae349f5Scvs2svn   FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
4421ae349f5Scvs2svn }
4431ae349f5Scvs2svn 
4441ae349f5Scvs2svn static void
4451ae349f5Scvs2svn IpcpLayerStart(struct fsm * fp)
4461ae349f5Scvs2svn {
4477308ec68SBrian Somers   /* We're about to start up ! */
4481ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerStart.\n");
449455aabc3SBrian Somers 
450455aabc3SBrian Somers   /* This is where we should be setting up the interface in AUTO mode */
4511ae349f5Scvs2svn }
4521ae349f5Scvs2svn 
4531ae349f5Scvs2svn static void
4541ae349f5Scvs2svn IpcpLayerFinish(struct fsm *fp)
4551ae349f5Scvs2svn {
4567308ec68SBrian Somers   /* We're now down */
4571ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerFinish.\n");
4581ae349f5Scvs2svn }
4591ae349f5Scvs2svn 
46068a0f0ccSBrian Somers void
46168a0f0ccSBrian Somers IpcpCleanInterface(struct fsm *fp)
46268a0f0ccSBrian Somers {
46368a0f0ccSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
46468a0f0ccSBrian Somers   struct ifaliasreq ifra;
46568a0f0ccSBrian Somers   struct sockaddr_in *me, *peer;
46668a0f0ccSBrian Somers   int s;
46768a0f0ccSBrian Somers 
46868a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
46968a0f0ccSBrian Somers   if (s < 0) {
47068a0f0ccSBrian Somers     LogPrintf(LogERROR, "IpcpCleanInterface: socket: %s\n", strerror(errno));
47168a0f0ccSBrian Somers     return;
47268a0f0ccSBrian Somers   }
47368a0f0ccSBrian Somers 
47468a0f0ccSBrian Somers   if (Enabled(ConfProxy))
475503a7782SBrian Somers     cifproxyarp(fp->bundle, ipcp->peer_ifip, s);
47668a0f0ccSBrian Somers 
477503a7782SBrian Somers   if (ipcp->my_ifip.s_addr != INADDR_ANY ||
478503a7782SBrian Somers       ipcp->peer_ifip.s_addr != INADDR_ANY) {
47968a0f0ccSBrian Somers     memset(&ifra, '\0', sizeof ifra);
48068a0f0ccSBrian Somers     strncpy(ifra.ifra_name, fp->bundle->ifname, sizeof ifra.ifra_name - 1);
48168a0f0ccSBrian Somers     ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
48268a0f0ccSBrian Somers     me = (struct sockaddr_in *)&ifra.ifra_addr;
48368a0f0ccSBrian Somers     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
48468a0f0ccSBrian Somers     me->sin_family = peer->sin_family = AF_INET;
48568a0f0ccSBrian Somers     me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
486503a7782SBrian Somers     me->sin_addr = ipcp->my_ifip;
487503a7782SBrian Somers     peer->sin_addr = ipcp->peer_ifip;
48868a0f0ccSBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
48968a0f0ccSBrian Somers       LogPrintf(LogERROR, "IpcpCleanInterface: ioctl(SIOCDIFADDR): %s\n",
49068a0f0ccSBrian Somers                 strerror(errno));
49168a0f0ccSBrian Somers       close(s);
49268a0f0ccSBrian Somers     }
493503a7782SBrian Somers     ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY;
49468a0f0ccSBrian Somers   }
49568a0f0ccSBrian Somers 
49668a0f0ccSBrian Somers   close(s);
49768a0f0ccSBrian Somers }
49868a0f0ccSBrian Somers 
4991ae349f5Scvs2svn static void
5001ae349f5Scvs2svn IpcpLayerDown(struct fsm *fp)
5011ae349f5Scvs2svn {
5027308ec68SBrian Somers   /* About to come down */
503aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
504455aabc3SBrian Somers   const char *s;
505455aabc3SBrian Somers 
506503a7782SBrian Somers   s = inet_ntoa(ipcp->peer_ifip);
507455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerDown: %s\n", s);
508455aabc3SBrian Somers 
50983d1af55SBrian Somers   throughput_stop(&ipcp->throughput);
51083d1af55SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
511455aabc3SBrian Somers 
512455aabc3SBrian Somers   /*
513455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
514455aabc3SBrian Somers    * associate executable sections in files with events.
515455aabc3SBrian Somers    */
516455aabc3SBrian Somers   if (SelectSystem(fp->bundle, s, LINKDOWNFILE) < 0)
517455aabc3SBrian Somers     if (GetLabel()) {
518455aabc3SBrian Somers        if (SelectSystem(fp->bundle, GetLabel(), LINKDOWNFILE) < 0)
519455aabc3SBrian Somers        SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE);
520455aabc3SBrian Somers     } else
521455aabc3SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE);
522455aabc3SBrian Somers 
52368a0f0ccSBrian Somers   if (!(mode & MODE_AUTO))
52468a0f0ccSBrian Somers     IpcpCleanInterface(fp);
5251ae349f5Scvs2svn }
5261ae349f5Scvs2svn 
5271ae349f5Scvs2svn static void
5281ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp)
5291ae349f5Scvs2svn {
5307308ec68SBrian Somers   /* We're now up */
531aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
5321ae349f5Scvs2svn   char tbuff[100];
5331ae349f5Scvs2svn 
5341ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state);
535503a7782SBrian Somers   snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
536455aabc3SBrian Somers   LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n",
537503a7782SBrian Somers 	    tbuff, inet_ntoa(ipcp->peer_ip));
5381ae349f5Scvs2svn 
539503a7782SBrian Somers   if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
540503a7782SBrian Somers     VjInit((ipcp->peer_compproto >> 8) & 255);
5411ae349f5Scvs2svn 
542503a7782SBrian Somers   if (ipcp_SetIPaddress(fp->bundle, ipcp, ipcp->my_ip,
543503a7782SBrian Somers                         ipcp->peer_ip, ifnetmask, 0) < 0) {
5441ae349f5Scvs2svn     LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
5451ae349f5Scvs2svn     return;
5461ae349f5Scvs2svn   }
547455aabc3SBrian Somers 
5481ae349f5Scvs2svn #ifndef NOALIAS
5491ae349f5Scvs2svn   if (mode & MODE_ALIAS)
550503a7782SBrian Somers     VarPacketAliasSetAddress(ipcp->my_ip);
5511ae349f5Scvs2svn #endif
552455aabc3SBrian Somers 
553455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerUp: %s\n",
554503a7782SBrian Somers             inet_ntoa(ipcp->peer_ifip));
555455aabc3SBrian Somers 
556455aabc3SBrian Somers   /*
557455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
558455aabc3SBrian Somers    * associate executable sections in files with events.
559455aabc3SBrian Somers    */
560503a7782SBrian Somers   if (SelectSystem(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE) < 0)
561455aabc3SBrian Somers     if (GetLabel()) {
562455aabc3SBrian Somers       if (SelectSystem(fp->bundle, GetLabel(), LINKUPFILE) < 0)
563455aabc3SBrian Somers         SelectSystem(fp->bundle, "MYADDR", LINKUPFILE);
564455aabc3SBrian Somers     } else
565455aabc3SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKUPFILE);
566455aabc3SBrian Somers 
56783d1af55SBrian Somers   throughput_start(&ipcp->throughput);
5681ae349f5Scvs2svn   StartIdleTimer();
56985b542cfSBrian Somers   prompt_Display(&prompt, fp->bundle);
5701ae349f5Scvs2svn }
5711ae349f5Scvs2svn 
5721ae349f5Scvs2svn void
5731ae349f5Scvs2svn IpcpUp()
5741ae349f5Scvs2svn {
5757308ec68SBrian Somers   /* Lower layers are ready.... go */
5767308ec68SBrian Somers   FsmUp(&IpcpInfo.fsm);
5771ae349f5Scvs2svn   LogPrintf(LogIPCP, "IPCP Up event!!\n");
5781ae349f5Scvs2svn }
5791ae349f5Scvs2svn 
5801ae349f5Scvs2svn void
5811ae349f5Scvs2svn IpcpOpen()
5821ae349f5Scvs2svn {
5837308ec68SBrian Somers   /* Start IPCP please */
5847308ec68SBrian Somers   FsmOpen(&IpcpInfo.fsm);
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
60183d1af55SBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type)
6021ae349f5Scvs2svn {
6037308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
604aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
6051ae349f5Scvs2svn   int type, length;
6061ae349f5Scvs2svn   u_long *lp, compproto;
6071ae349f5Scvs2svn   struct compreq *pcomp;
6081ae349f5Scvs2svn   struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
6091ae349f5Scvs2svn   char tbuff[100];
6101ae349f5Scvs2svn   char tbuff2[100];
6111ae349f5Scvs2svn 
6121ae349f5Scvs2svn   ackp = AckBuff;
6131ae349f5Scvs2svn   nakp = NakBuff;
6141ae349f5Scvs2svn   rejp = RejBuff;
6151ae349f5Scvs2svn 
6161ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
6171ae349f5Scvs2svn     type = *cp;
6181ae349f5Scvs2svn     length = cp[1];
6191ae349f5Scvs2svn     if (type < NCFTYPES)
6201ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
6211ae349f5Scvs2svn     else if (type > 128 && type < 128 + NCFTYPES128)
6221ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
6231ae349f5Scvs2svn     else
6241ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
6251ae349f5Scvs2svn 
6261ae349f5Scvs2svn     switch (type) {
6271ae349f5Scvs2svn     case TY_IPADDR:		/* RFC1332 */
6281ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6291ae349f5Scvs2svn       ipaddr.s_addr = *lp;
6301ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
6311ae349f5Scvs2svn 
6321ae349f5Scvs2svn       switch (mode_type) {
6331ae349f5Scvs2svn       case MODE_REQ:
634503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
6351ae349f5Scvs2svn           if (ipaddr.s_addr == INADDR_ANY ||
636503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
637503a7782SBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp, ipcp->cfg.my_range.ipaddr,
638455aabc3SBrian Somers                                 ipaddr, ifnetmask, 1)) {
6391ae349f5Scvs2svn             LogPrintf(LogIPCP, "%s: Address invalid or already in use\n",
6401ae349f5Scvs2svn                       inet_ntoa(ipaddr));
641503a7782SBrian Somers             ipcp->peer_ip = ChooseHisAddr
642503a7782SBrian Somers               (fp->bundle, ipcp, ipcp->cfg.my_range.ipaddr);
643503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
6441ae349f5Scvs2svn 	      memcpy(rejp, cp, length);
6451ae349f5Scvs2svn 	      rejp += length;
6461ae349f5Scvs2svn             } else {
6471ae349f5Scvs2svn 	      memcpy(nakp, cp, 2);
648503a7782SBrian Somers 	      memcpy(nakp+2, &ipcp->peer_ip.s_addr, length - 2);
6491ae349f5Scvs2svn 	      nakp += length;
6501ae349f5Scvs2svn             }
6511ae349f5Scvs2svn 	    break;
6521ae349f5Scvs2svn           }
653503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
6541ae349f5Scvs2svn 	  /*
6551ae349f5Scvs2svn 	   * If destination address is not acceptable, insist to use what we
6561ae349f5Scvs2svn 	   * want to use.
6571ae349f5Scvs2svn 	   */
6581ae349f5Scvs2svn 	  memcpy(nakp, cp, 2);
659503a7782SBrian Somers 	  memcpy(nakp+2, &ipcp->peer_ip.s_addr, length - 2);
6601ae349f5Scvs2svn 	  nakp += length;
6611ae349f5Scvs2svn 	  break;
6621ae349f5Scvs2svn 	}
663503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
6641ae349f5Scvs2svn 	memcpy(ackp, cp, length);
6651ae349f5Scvs2svn 	ackp += length;
6661ae349f5Scvs2svn 	break;
6671ae349f5Scvs2svn       case MODE_NAK:
668503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
6691ae349f5Scvs2svn 	  /* Use address suggested by peer */
6701ae349f5Scvs2svn 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
671503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
6721ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
673503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
6741ae349f5Scvs2svn 	} else {
6751ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
67683d1af55SBrian Somers           FsmClose(&ipcp->fsm);
6771ae349f5Scvs2svn 	}
6781ae349f5Scvs2svn 	break;
6791ae349f5Scvs2svn       case MODE_REJ:
680503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
6811ae349f5Scvs2svn 	break;
6821ae349f5Scvs2svn       }
6831ae349f5Scvs2svn       break;
6841ae349f5Scvs2svn     case TY_COMPPROTO:
6851ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6861ae349f5Scvs2svn       compproto = htonl(*lp);
6871ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
6881ae349f5Scvs2svn 
6891ae349f5Scvs2svn       switch (mode_type) {
6901ae349f5Scvs2svn       case MODE_REQ:
6911ae349f5Scvs2svn 	if (!Acceptable(ConfVjcomp)) {
6921ae349f5Scvs2svn 	  memcpy(rejp, cp, length);
6931ae349f5Scvs2svn 	  rejp += length;
6941ae349f5Scvs2svn 	} else {
6951ae349f5Scvs2svn 	  pcomp = (struct compreq *) (cp + 2);
6961ae349f5Scvs2svn 	  switch (length) {
6971ae349f5Scvs2svn 	  case 4:		/* RFC1172 */
6981ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
6991ae349f5Scvs2svn 	      LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
70083d1af55SBrian Somers 	      ipcp->heis1172 = 1;
701503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
7021ae349f5Scvs2svn 	      memcpy(ackp, cp, length);
7031ae349f5Scvs2svn 	      ackp += length;
7041ae349f5Scvs2svn 	    } else {
7051ae349f5Scvs2svn 	      memcpy(nakp, cp, 2);
7061ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
7071ae349f5Scvs2svn 	      memcpy(nakp+2, &pcomp, 2);
7081ae349f5Scvs2svn 	      nakp += length;
7091ae349f5Scvs2svn 	    }
7101ae349f5Scvs2svn 	    break;
7111ae349f5Scvs2svn 	  case 6:		/* RFC1332 */
7121ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
713503a7782SBrian Somers 		&& pcomp->slots <= MAX_VJ_STATES
714503a7782SBrian Somers                 && pcomp->slots >= MIN_VJ_STATES) {
715503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
71683d1af55SBrian Somers 	      ipcp->heis1172 = 0;
7171ae349f5Scvs2svn 	      memcpy(ackp, cp, length);
7181ae349f5Scvs2svn 	      ackp += length;
7191ae349f5Scvs2svn 	    } else {
7201ae349f5Scvs2svn 	      memcpy(nakp, cp, 2);
7211ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
722503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
7231ae349f5Scvs2svn 	      pcomp->compcid = 0;
7241ae349f5Scvs2svn 	      memcpy(nakp+2, &pcomp, sizeof pcomp);
7251ae349f5Scvs2svn 	      nakp += length;
7261ae349f5Scvs2svn 	    }
7271ae349f5Scvs2svn 	    break;
7281ae349f5Scvs2svn 	  default:
7291ae349f5Scvs2svn 	    memcpy(rejp, cp, length);
7301ae349f5Scvs2svn 	    rejp += length;
7311ae349f5Scvs2svn 	    break;
7321ae349f5Scvs2svn 	  }
7331ae349f5Scvs2svn 	}
7341ae349f5Scvs2svn 	break;
7351ae349f5Scvs2svn       case MODE_NAK:
7361ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
737503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
738503a7782SBrian Somers 	ipcp->my_compproto = compproto;
7391ae349f5Scvs2svn 	break;
7401ae349f5Scvs2svn       case MODE_REJ:
741503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
7421ae349f5Scvs2svn 	break;
7431ae349f5Scvs2svn       }
7441ae349f5Scvs2svn       break;
7451ae349f5Scvs2svn     case TY_IPADDRS:		/* RFC1172 */
7461ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
7471ae349f5Scvs2svn       ipaddr.s_addr = *lp;
7481ae349f5Scvs2svn       lp = (u_long *) (cp + 6);
7491ae349f5Scvs2svn       dstipaddr.s_addr = *lp;
7501ae349f5Scvs2svn       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
7511ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
7521ae349f5Scvs2svn 
7531ae349f5Scvs2svn       switch (mode_type) {
7541ae349f5Scvs2svn       case MODE_REQ:
755503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
756503a7782SBrian Somers 	ipcp->my_ip = dstipaddr;
7571ae349f5Scvs2svn 	memcpy(ackp, cp, length);
7581ae349f5Scvs2svn 	ackp += length;
7591ae349f5Scvs2svn 	break;
7601ae349f5Scvs2svn       case MODE_NAK:
7611ae349f5Scvs2svn         snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
762503a7782SBrian Somers 		 inet_ntoa(ipcp->my_ip));
7631ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
764503a7782SBrian Somers 	ipcp->my_ip = ipaddr;
765503a7782SBrian Somers 	ipcp->peer_ip = dstipaddr;
7661ae349f5Scvs2svn 	break;
7671ae349f5Scvs2svn       case MODE_REJ:
768503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
7691ae349f5Scvs2svn 	break;
7701ae349f5Scvs2svn       }
7711ae349f5Scvs2svn       break;
7721ae349f5Scvs2svn 
7731ae349f5Scvs2svn       /*
7741ae349f5Scvs2svn        * MS extensions for MS's PPP
7751ae349f5Scvs2svn        */
7761ae349f5Scvs2svn 
7771ae349f5Scvs2svn #ifndef NOMSEXT
7781ae349f5Scvs2svn     case TY_PRIMARY_DNS:	/* MS PPP DNS negotiation hack */
7791ae349f5Scvs2svn     case TY_SECONDARY_DNS:
7801ae349f5Scvs2svn       if (!Enabled(ConfMSExt)) {
7811ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n");
78283d1af55SBrian Somers 	ipcp->my_reject |= (1 << type);
7831ae349f5Scvs2svn 	memcpy(rejp, cp, length);
7841ae349f5Scvs2svn 	rejp += length;
7851ae349f5Scvs2svn 	break;
7861ae349f5Scvs2svn       }
7871ae349f5Scvs2svn       switch (mode_type) {
7881ae349f5Scvs2svn       case MODE_REQ:
7891ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
7901ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
791503a7782SBrian Somers 	ms_info_req.s_addr = ipcp->cfg.ns_entries
79229e275ceSBrian Somers           [(type - TY_PRIMARY_DNS) ? 1 : 0].s_addr;
7931ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
7941ae349f5Scvs2svn 
7951ae349f5Scvs2svn 	  /*
7961ae349f5Scvs2svn 	   * So the client has got the DNS stuff wrong (first request) so
7971ae349f5Scvs2svn 	   * we'll tell 'em how it is
7981ae349f5Scvs2svn 	   */
7991ae349f5Scvs2svn 	  memcpy(nakp, cp, 2);	/* copy first two (type/length) */
8001ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n",
8011ae349f5Scvs2svn 		    type,
8021ae349f5Scvs2svn 		    inet_ntoa(dnsstuff),
8031ae349f5Scvs2svn 		    inet_ntoa(ms_info_req));
8041ae349f5Scvs2svn 	  memcpy(nakp+2, &ms_info_req, length);
8051ae349f5Scvs2svn 	  nakp += length;
8061ae349f5Scvs2svn 	  break;
8071ae349f5Scvs2svn 	}
8081ae349f5Scvs2svn 
8091ae349f5Scvs2svn 	/*
8101ae349f5Scvs2svn 	 * Otherwise they have it right (this time) so we send a ack packet
8111ae349f5Scvs2svn 	 * back confirming it... end of story
8121ae349f5Scvs2svn 	 */
8131ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n",
8141ae349f5Scvs2svn 		  type,
8151ae349f5Scvs2svn 		  inet_ntoa(ms_info_req));
8161ae349f5Scvs2svn 	memcpy(ackp, cp, length);
8171ae349f5Scvs2svn 	ackp += length;
8181ae349f5Scvs2svn 	break;
8191ae349f5Scvs2svn       case MODE_NAK:		/* what does this mean?? */
8201ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type);
8211ae349f5Scvs2svn 	break;
8221ae349f5Scvs2svn       case MODE_REJ:		/* confused?? me to :) */
8231ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type);
8241ae349f5Scvs2svn 	break;
8251ae349f5Scvs2svn       }
8261ae349f5Scvs2svn       break;
8271ae349f5Scvs2svn 
8281ae349f5Scvs2svn     case TY_PRIMARY_NBNS:	/* MS PPP NetBIOS nameserver hack */
8291ae349f5Scvs2svn     case TY_SECONDARY_NBNS:
8301ae349f5Scvs2svn       if (!Enabled(ConfMSExt)) {
8311ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n");
83283d1af55SBrian Somers 	ipcp->my_reject |= (1 << type);
8331ae349f5Scvs2svn 	memcpy(rejp, cp, length);
8341ae349f5Scvs2svn 	rejp += length;
8351ae349f5Scvs2svn 	break;
8361ae349f5Scvs2svn       }
8371ae349f5Scvs2svn       switch (mode_type) {
8381ae349f5Scvs2svn       case MODE_REQ:
8391ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
8401ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
841503a7782SBrian Somers 	ms_info_req.s_addr = ipcp->cfg.nbns_entries
84229e275ceSBrian Somers           [(type - TY_PRIMARY_NBNS) ? 1 : 0].s_addr;
8431ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
8441ae349f5Scvs2svn 	  memcpy(nakp, cp, 2);
8451ae349f5Scvs2svn 	  memcpy(nakp+2, &ms_info_req.s_addr, length);
8461ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n",
8471ae349f5Scvs2svn 		    type,
8481ae349f5Scvs2svn 		    inet_ntoa(dnsstuff),
8491ae349f5Scvs2svn 		    inet_ntoa(ms_info_req));
8501ae349f5Scvs2svn 	  nakp += length;
8511ae349f5Scvs2svn 	  break;
8521ae349f5Scvs2svn 	}
8531ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n",
8541ae349f5Scvs2svn 		  type,
8551ae349f5Scvs2svn 		  inet_ntoa(ms_info_req));
8561ae349f5Scvs2svn 	memcpy(ackp, cp, length);
8571ae349f5Scvs2svn 	ackp += length;
8581ae349f5Scvs2svn 	break;
8591ae349f5Scvs2svn       case MODE_NAK:
8601ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
8611ae349f5Scvs2svn 	break;
8621ae349f5Scvs2svn       case MODE_REJ:
8631ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
8641ae349f5Scvs2svn 	break;
8651ae349f5Scvs2svn       }
8661ae349f5Scvs2svn       break;
8671ae349f5Scvs2svn 
8681ae349f5Scvs2svn #endif
8691ae349f5Scvs2svn 
8701ae349f5Scvs2svn     default:
87183d1af55SBrian Somers       ipcp->my_reject |= (1 << type);
8721ae349f5Scvs2svn       memcpy(rejp, cp, length);
8731ae349f5Scvs2svn       rejp += length;
8741ae349f5Scvs2svn       break;
8751ae349f5Scvs2svn     }
8761ae349f5Scvs2svn     plen -= length;
8771ae349f5Scvs2svn     cp += length;
8781ae349f5Scvs2svn   }
8791ae349f5Scvs2svn }
8801ae349f5Scvs2svn 
8811ae349f5Scvs2svn void
8821ae349f5Scvs2svn IpcpInput(struct mbuf * bp)
8831ae349f5Scvs2svn {
8847308ec68SBrian Somers   /* Got PROTO_IPCP from link */
8857308ec68SBrian Somers   FsmInput(&IpcpInfo.fsm, bp);
8861ae349f5Scvs2svn }
8871ae349f5Scvs2svn 
8881ae349f5Scvs2svn int
8897a6f8720SBrian Somers UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
8901ae349f5Scvs2svn {
8917308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
892503a7782SBrian Somers   memset(&IpcpInfo.cfg.peer_range, '\0', sizeof IpcpInfo.cfg.peer_range);
893503a7782SBrian Somers   iplist_reset(&IpcpInfo.cfg.peer_list);
8941ae349f5Scvs2svn   if (strpbrk(hisaddr, ",-")) {
895503a7782SBrian Somers     iplist_setsrc(&IpcpInfo.cfg.peer_list, hisaddr);
896503a7782SBrian Somers     if (iplist_isvalid(&IpcpInfo.cfg.peer_list)) {
897503a7782SBrian Somers       iplist_setrandpos(&IpcpInfo.cfg.peer_list);
898503a7782SBrian Somers       IpcpInfo.peer_ip = ChooseHisAddr
899503a7782SBrian Somers         (bundle, &IpcpInfo, IpcpInfo.my_ip);
900503a7782SBrian Somers       if (IpcpInfo.peer_ip.s_addr == INADDR_ANY) {
901503a7782SBrian Somers         LogPrintf(LogWARN, "%s: None available !\n", IpcpInfo.cfg.peer_list.src);
9021ae349f5Scvs2svn         return(0);
9031ae349f5Scvs2svn       }
904503a7782SBrian Somers       IpcpInfo.cfg.peer_range.ipaddr.s_addr = IpcpInfo.peer_ip.s_addr;
905503a7782SBrian Somers       IpcpInfo.cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
906503a7782SBrian Somers       IpcpInfo.cfg.peer_range.width = 32;
9071ae349f5Scvs2svn     } else {
9081ae349f5Scvs2svn       LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr);
9091ae349f5Scvs2svn       return 0;
9101ae349f5Scvs2svn     }
911503a7782SBrian Somers   } else if (ParseAddr(1, &hisaddr, &IpcpInfo.cfg.peer_range.ipaddr,
912503a7782SBrian Somers 		       &IpcpInfo.cfg.peer_range.mask,
913503a7782SBrian Somers                        &IpcpInfo.cfg.peer_range.width) != 0) {
914503a7782SBrian Somers     IpcpInfo.peer_ip.s_addr = IpcpInfo.cfg.peer_range.ipaddr.s_addr;
9151ae349f5Scvs2svn 
916455aabc3SBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, &IpcpInfo,
917503a7782SBrian Somers                                      IpcpInfo.cfg.my_range.ipaddr,
918503a7782SBrian Somers                                      IpcpInfo.cfg.peer_range.ipaddr, ifnetmask,
919455aabc3SBrian Somers                                      0) < 0) {
920503a7782SBrian Somers       IpcpInfo.cfg.my_range.ipaddr.s_addr = INADDR_ANY;
921503a7782SBrian Somers       IpcpInfo.cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
9221ae349f5Scvs2svn       return 0;
9231ae349f5Scvs2svn     }
9241ae349f5Scvs2svn   } else
9251ae349f5Scvs2svn     return 0;
9261ae349f5Scvs2svn 
9271ae349f5Scvs2svn   return 1;
9281ae349f5Scvs2svn }
929