xref: /freebsd/usr.sbin/ppp/ipcp.c (revision eaa4df37f41891389081dc62e17cc172b36b8736)
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  *
20eaa4df37SBrian Somers  * $Id: ipcp.c,v 1.50.2.23 1998/03/16 22:52:20 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"
567a6f8720SBrian Somers #include "bundle.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"
658c07a7b2SBrian Somers #include "link.h"
6642d4d396SBrian Somers #include "descriptor.h"
6763b73463SBrian Somers #include "physical.h"
68455aabc3SBrian Somers #include "id.h"
69455aabc3SBrian Somers #include "arp.h"
70455aabc3SBrian Somers #include "systems.h"
7185b542cfSBrian Somers #include "prompt.h"
721ae349f5Scvs2svn 
73503a7782SBrian Somers #undef REJECTED
74503a7782SBrian Somers #define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
75503a7782SBrian Somers 
7629e275ceSBrian Somers struct compreq {
7729e275ceSBrian Somers   u_short proto;
7829e275ceSBrian Somers   u_char slots;
7929e275ceSBrian Somers   u_char compcid;
8029e275ceSBrian Somers };
811ae349f5Scvs2svn 
821ae349f5Scvs2svn static void IpcpLayerUp(struct fsm *);
831ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *);
847308ec68SBrian Somers static void IpcpLayerStart(struct fsm *);
857308ec68SBrian Somers static void IpcpLayerFinish(struct fsm *);
861ae349f5Scvs2svn static void IpcpInitRestartCounter(struct fsm *);
877308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *);
887308ec68SBrian Somers static void IpcpSendTerminateReq(struct fsm *);
897308ec68SBrian Somers static void IpcpSendTerminateAck(struct fsm *);
9030c2f2ffSBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
9130c2f2ffSBrian Somers                              struct fsm_decode *);
9283d1af55SBrian Somers 
9383d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = {
9483d1af55SBrian Somers   IpcpLayerUp,
9583d1af55SBrian Somers   IpcpLayerDown,
9683d1af55SBrian Somers   IpcpLayerStart,
976d666775SBrian Somers   IpcpLayerFinish,
9883d1af55SBrian Somers   IpcpInitRestartCounter,
9983d1af55SBrian Somers   IpcpSendConfigReq,
10083d1af55SBrian Somers   IpcpSendTerminateReq,
10183d1af55SBrian Somers   IpcpSendTerminateAck,
10283d1af55SBrian Somers   IpcpDecodeConfig,
103503a7782SBrian Somers   NullRecvResetReq,
104503a7782SBrian Somers   NullRecvResetAck
10583d1af55SBrian Somers };
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
1295828db6dSBrian Somers ipcp_AddInOctets(struct ipcp *ipcp, int n)
1301ae349f5Scvs2svn {
1315828db6dSBrian Somers   throughput_addin(&ipcp->throughput, n);
1321ae349f5Scvs2svn }
1331ae349f5Scvs2svn 
1341ae349f5Scvs2svn void
1355828db6dSBrian Somers ipcp_AddOutOctets(struct ipcp *ipcp, int n)
1361ae349f5Scvs2svn {
1375828db6dSBrian Somers   throughput_addout(&ipcp->throughput, n);
1381ae349f5Scvs2svn }
1391ae349f5Scvs2svn 
1401ae349f5Scvs2svn int
1411ae349f5Scvs2svn ReportIpcpStatus(struct cmdargs const *arg)
1421ae349f5Scvs2svn {
1435828db6dSBrian Somers   prompt_Printf(&prompt, "%s [%s]\n", arg->bundle->ncp.ipcp.fsm.name,
1445828db6dSBrian Somers           StateNames[arg->bundle->ncp.ipcp.fsm.state]);
1455828db6dSBrian Somers   if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) {
14685b542cfSBrian Somers     prompt_Printf(&prompt, " His side:               %s, %s\n",
1475828db6dSBrian Somers 	    inet_ntoa(arg->bundle->ncp.ipcp.peer_ip),
1485828db6dSBrian Somers             vj2asc(arg->bundle->ncp.ipcp.peer_compproto));
14985b542cfSBrian Somers     prompt_Printf(&prompt, " My side:                %s, %s\n",
1505828db6dSBrian Somers 	    inet_ntoa(arg->bundle->ncp.ipcp.my_ip),
1515828db6dSBrian Somers             vj2asc(arg->bundle->ncp.ipcp.my_compproto));
1521ae349f5Scvs2svn   }
1531ae349f5Scvs2svn 
15485b542cfSBrian Somers   prompt_Printf(&prompt, "\nDefaults:\n");
15585b542cfSBrian Somers   prompt_Printf(&prompt, " My Address:             %s/%d\n",
1565828db6dSBrian Somers 	  inet_ntoa(arg->bundle->ncp.ipcp.cfg.my_range.ipaddr),
1575828db6dSBrian Somers           arg->bundle->ncp.ipcp.cfg.my_range.width);
1585828db6dSBrian Somers   if (iplist_isvalid(&arg->bundle->ncp.ipcp.cfg.peer_list))
15985b542cfSBrian Somers     prompt_Printf(&prompt, " His Address:            %s\n",
1605828db6dSBrian Somers             arg->bundle->ncp.ipcp.cfg.peer_list.src);
1611ae349f5Scvs2svn   else
16285b542cfSBrian Somers     prompt_Printf(&prompt, " His Address:            %s/%d\n",
1635828db6dSBrian Somers 	  inet_ntoa(arg->bundle->ncp.ipcp.cfg.peer_range.ipaddr),
1645828db6dSBrian Somers           arg->bundle->ncp.ipcp.cfg.peer_range.width);
1655828db6dSBrian Somers   if (arg->bundle->ncp.ipcp.cfg.HaveTriggerAddress)
16685b542cfSBrian Somers     prompt_Printf(&prompt, " Negotiation(trigger):   %s\n",
1675828db6dSBrian Somers             inet_ntoa(arg->bundle->ncp.ipcp.cfg.TriggerAddress));
1681ae349f5Scvs2svn   else
16985b542cfSBrian Somers     prompt_Printf(&prompt, " Negotiation(trigger):   MYADDR\n");
170503a7782SBrian Somers   prompt_Printf(&prompt, " Initial VJ slots:       %d\n",
1715828db6dSBrian Somers                 arg->bundle->ncp.ipcp.cfg.VJInitSlots);
17285b542cfSBrian Somers   prompt_Printf(&prompt, " Initial VJ compression: %s\n",
1735828db6dSBrian Somers           arg->bundle->ncp.ipcp.cfg.VJInitComp ? "on" : "off");
1741ae349f5Scvs2svn 
17585b542cfSBrian Somers   prompt_Printf(&prompt, "\n");
1765828db6dSBrian Somers   throughput_disp(&arg->bundle->ncp.ipcp.throughput);
1771ae349f5Scvs2svn 
1781ae349f5Scvs2svn   return 0;
1791ae349f5Scvs2svn }
1801ae349f5Scvs2svn 
1811ae349f5Scvs2svn int
1825828db6dSBrian Somers SetInitVJ(struct cmdargs const *arg)
1831ae349f5Scvs2svn {
1845828db6dSBrian Somers   if (arg->argc != 2)
1851ae349f5Scvs2svn     return -1;
1865828db6dSBrian Somers   if (!strcasecmp(arg->argv[0], "slots")) {
1871ae349f5Scvs2svn     int slots;
1881ae349f5Scvs2svn 
1895828db6dSBrian Somers     slots = atoi(arg->argv[1]);
1901ae349f5Scvs2svn     if (slots < 4 || slots > 16)
1911ae349f5Scvs2svn       return 1;
1925828db6dSBrian Somers     arg->bundle->ncp.ipcp.cfg.VJInitSlots = slots;
1931ae349f5Scvs2svn     return 0;
1945828db6dSBrian Somers   } else if (!strcasecmp(arg->argv[0], "slotcomp")) {
1955828db6dSBrian Somers     if (!strcasecmp(arg->argv[1], "on"))
1965828db6dSBrian Somers       arg->bundle->ncp.ipcp.cfg.VJInitComp = 1;
1975828db6dSBrian Somers     else if (!strcasecmp(arg->argv[1], "off"))
1985828db6dSBrian Somers       arg->bundle->ncp.ipcp.cfg.VJInitComp = 0;
1991ae349f5Scvs2svn     else
2001ae349f5Scvs2svn       return 2;
2011ae349f5Scvs2svn     return 0;
2021ae349f5Scvs2svn   }
2031ae349f5Scvs2svn   return -1;
2041ae349f5Scvs2svn }
2051ae349f5Scvs2svn 
2061ae349f5Scvs2svn void
2076d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
2086d666775SBrian Somers           const struct fsm_parent *parent)
2091ae349f5Scvs2svn {
210503a7782SBrian Somers   struct hostent *hp;
211503a7782SBrian Somers   char name[MAXHOSTNAMELEN];
21229e275ceSBrian Somers 
213503a7782SBrian Somers   fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, IPCP_MAXCODE, 10, LogIPCP,
2146d666775SBrian Somers            bundle, l, parent, &ipcp_Callbacks);
215503a7782SBrian Somers 
216503a7782SBrian Somers   ipcp->cfg.VJInitSlots = DEF_VJ_STATES;
217503a7782SBrian Somers   ipcp->cfg.VJInitComp = 1;
218503a7782SBrian Somers   memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
219503a7782SBrian Somers   if (gethostname(name, sizeof name) == 0) {
220503a7782SBrian Somers     hp = gethostbyname(name);
221503a7782SBrian Somers     if (hp && hp->h_addrtype == AF_INET) {
222503a7782SBrian Somers       memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
223503a7782SBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
224503a7782SBrian Somers       ipcp->cfg.peer_range.width = 32;
2251ae349f5Scvs2svn     }
226503a7782SBrian Somers   }
22730c2f2ffSBrian Somers   ipcp->cfg.netmask.s_addr = INADDR_ANY;
228503a7782SBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
229503a7782SBrian Somers   iplist_setsrc(&ipcp->cfg.peer_list, "");
230503a7782SBrian Somers   ipcp->cfg.HaveTriggerAddress = 0;
231503a7782SBrian Somers 
232503a7782SBrian Somers   ipcp->cfg.ns_entries[0].s_addr = INADDR_ANY;
233503a7782SBrian Somers   ipcp->cfg.ns_entries[1].s_addr = INADDR_ANY;
234503a7782SBrian Somers   ipcp->cfg.nbns_entries[0].s_addr = INADDR_ANY;
235503a7782SBrian Somers   ipcp->cfg.nbns_entries[1].s_addr = INADDR_ANY;
236503a7782SBrian Somers 
237eaa4df37SBrian Somers   memset(&ipcp->vj, '\0', sizeof ipcp->vj);
238eaa4df37SBrian Somers 
239503a7782SBrian Somers   ipcp->my_ifip.s_addr = INADDR_ANY;
240503a7782SBrian Somers   ipcp->peer_ifip.s_addr = INADDR_ANY;
241503a7782SBrian Somers 
242503a7782SBrian Somers   ipcp_Setup(ipcp);
243503a7782SBrian Somers }
244503a7782SBrian Somers 
245503a7782SBrian Somers void
246503a7782SBrian Somers ipcp_Setup(struct ipcp *ipcp)
247503a7782SBrian Somers {
248503a7782SBrian Somers   int pos;
249503a7782SBrian Somers 
250503a7782SBrian Somers   ipcp->fsm.open_mode = 0;
2515454ccd9SBrian Somers   ipcp->fsm.maxconfig = 10;
252503a7782SBrian Somers 
253503a7782SBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list)) {
254503a7782SBrian Somers     if (ipcp->my_ifip.s_addr != INADDR_ANY &&
255503a7782SBrian Somers         (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1)
256503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos);
257503a7782SBrian Somers     else
258503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
259503a7782SBrian Somers     ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
260503a7782SBrian Somers     ipcp->cfg.peer_range.width = 32;
261503a7782SBrian Somers   }
262503a7782SBrian Somers 
263503a7782SBrian Somers   ipcp->heis1172 = 0;
264503a7782SBrian Somers 
265503a7782SBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
266503a7782SBrian Somers   ipcp->peer_compproto = 0;
2671ae349f5Scvs2svn 
2681ae349f5Scvs2svn   /*
2691ae349f5Scvs2svn    * Some implementations of PPP require that we send a
2701ae349f5Scvs2svn    * *special* value as our address, even though the rfc specifies
2711ae349f5Scvs2svn    * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
2721ae349f5Scvs2svn    */
273503a7782SBrian Somers   if (ipcp->cfg.HaveTriggerAddress) {
274503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.TriggerAddress;
27529e275ceSBrian Somers     LogPrintf(LogIPCP, "Using trigger address %s\n",
276503a7782SBrian Somers               inet_ntoa(ipcp->cfg.TriggerAddress));
277503a7782SBrian Somers   } else
278503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
27929e275ceSBrian Somers 
2801ae349f5Scvs2svn   if (Enabled(ConfVjcomp))
281503a7782SBrian Somers     ipcp->my_compproto = (PROTO_VJCOMP << 16) +
282503a7782SBrian Somers                          ((ipcp->cfg.VJInitSlots - 1) << 8) +
283503a7782SBrian Somers                          ipcp->cfg.VJInitComp;
2841ae349f5Scvs2svn   else
285503a7782SBrian Somers     ipcp->my_compproto = 0;
286eaa4df37SBrian Somers   sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.VJInitSlots - 1);
28729e275ceSBrian Somers 
288503a7782SBrian Somers   ipcp->peer_reject = 0;
289503a7782SBrian Somers   ipcp->my_reject = 0;
290503a7782SBrian Somers 
291503a7782SBrian Somers   throughput_init(&ipcp->throughput);
2921ae349f5Scvs2svn }
2931ae349f5Scvs2svn 
294455aabc3SBrian Somers static int
29530c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
29630c2f2ffSBrian Somers                   struct in_addr hisaddr, int silent)
297455aabc3SBrian Somers {
298455aabc3SBrian Somers   struct sockaddr_in *sock_in;
299455aabc3SBrian Somers   int s;
300455aabc3SBrian Somers   u_long mask, addr;
301455aabc3SBrian Somers   struct ifaliasreq ifra;
302455aabc3SBrian Somers 
303455aabc3SBrian Somers   /* If given addresses are alreay set, then ignore this request */
30430c2f2ffSBrian Somers   if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr &&
30530c2f2ffSBrian Somers       bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr)
306455aabc3SBrian Somers     return 0;
307455aabc3SBrian Somers 
30830c2f2ffSBrian Somers   IpcpCleanInterface(&bundle->ncp.ipcp.fsm);
30968a0f0ccSBrian Somers 
310455aabc3SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
311455aabc3SBrian Somers   if (s < 0) {
312455aabc3SBrian Somers     LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
313455aabc3SBrian Somers     return (-1);
314455aabc3SBrian Somers   }
315455aabc3SBrian Somers 
316455aabc3SBrian Somers   memset(&ifra, '\0', sizeof ifra);
317455aabc3SBrian Somers   strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1);
318455aabc3SBrian Somers   ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
319455aabc3SBrian Somers 
320455aabc3SBrian Somers   /* Set interface address */
321455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
322455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
323455aabc3SBrian Somers   sock_in->sin_addr = myaddr;
324455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
325455aabc3SBrian Somers 
326455aabc3SBrian Somers   /* Set destination address */
327455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
328455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
329455aabc3SBrian Somers   sock_in->sin_addr = hisaddr;
330455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
331455aabc3SBrian Somers 
332455aabc3SBrian Somers   addr = ntohl(myaddr.s_addr);
333455aabc3SBrian Somers   if (IN_CLASSA(addr))
334455aabc3SBrian Somers     mask = IN_CLASSA_NET;
335455aabc3SBrian Somers   else if (IN_CLASSB(addr))
336455aabc3SBrian Somers     mask = IN_CLASSB_NET;
337455aabc3SBrian Somers   else
338455aabc3SBrian Somers     mask = IN_CLASSC_NET;
339455aabc3SBrian Somers 
340455aabc3SBrian Somers   /* if subnet mask is given, use it instead of class mask */
34130c2f2ffSBrian Somers   if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY &&
34230c2f2ffSBrian Somers       (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask)
34330c2f2ffSBrian Somers     mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr);
344455aabc3SBrian Somers 
345455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
346455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
347455aabc3SBrian Somers   sock_in->sin_addr.s_addr = htonl(mask);
348455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
349455aabc3SBrian Somers 
350455aabc3SBrian Somers   if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
351455aabc3SBrian Somers     if (!silent)
352455aabc3SBrian Somers       LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n",
353455aabc3SBrian Somers 		strerror(errno));
354455aabc3SBrian Somers     close(s);
355455aabc3SBrian Somers     return (-1);
356455aabc3SBrian Somers   }
357455aabc3SBrian Somers 
35830c2f2ffSBrian Somers   bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr;
35930c2f2ffSBrian Somers   bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr;
360455aabc3SBrian Somers 
361455aabc3SBrian Somers   if (Enabled(ConfProxy))
36230c2f2ffSBrian Somers     sifproxyarp(bundle, bundle->ncp.ipcp.peer_ifip, s);
363455aabc3SBrian Somers 
364455aabc3SBrian Somers   close(s);
365455aabc3SBrian Somers   return (0);
366455aabc3SBrian Somers }
367455aabc3SBrian Somers 
368455aabc3SBrian Somers static struct in_addr
36930c2f2ffSBrian Somers ChooseHisAddr(struct bundle *bundle, const struct in_addr gw)
370455aabc3SBrian Somers {
371455aabc3SBrian Somers   struct in_addr try;
372455aabc3SBrian Somers   int f;
373455aabc3SBrian Somers 
3745828db6dSBrian Somers   for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
3755828db6dSBrian Somers     try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
376455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
377455aabc3SBrian Somers               f, inet_ntoa(try));
37830c2f2ffSBrian Somers     if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
379455aabc3SBrian Somers       LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
380455aabc3SBrian Somers                 inet_ntoa(try));
381455aabc3SBrian Somers       break;
382455aabc3SBrian Somers     }
383455aabc3SBrian Somers   }
384455aabc3SBrian Somers 
3855828db6dSBrian Somers   if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
386455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
387455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
388455aabc3SBrian Somers   }
389455aabc3SBrian Somers 
390455aabc3SBrian Somers   return try;
391455aabc3SBrian Somers }
392455aabc3SBrian Somers 
3931ae349f5Scvs2svn static void
3941ae349f5Scvs2svn IpcpInitRestartCounter(struct fsm * fp)
3951ae349f5Scvs2svn {
3967308ec68SBrian Somers   /* Set fsm timer load */
3971ae349f5Scvs2svn   fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
3981ae349f5Scvs2svn   fp->restart = 5;
3991ae349f5Scvs2svn }
4001ae349f5Scvs2svn 
4011ae349f5Scvs2svn static void
4021ae349f5Scvs2svn IpcpSendConfigReq(struct fsm *fp)
4031ae349f5Scvs2svn {
4047308ec68SBrian Somers   /* Send config REQ please */
4058c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
406aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
40730c2f2ffSBrian Somers   u_char *cp, buff[12];
4081ae349f5Scvs2svn   struct lcp_opt o;
4091ae349f5Scvs2svn 
4101ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpSendConfigReq\n");
41130c2f2ffSBrian Somers   cp = buff;
41230c2f2ffSBrian Somers 
41383d1af55SBrian Somers   if ((p && !Physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
4141ae349f5Scvs2svn     o.id = TY_IPADDR;
4151ae349f5Scvs2svn     o.len = 6;
416503a7782SBrian Somers     *(u_long *)o.data = ipcp->my_ip.s_addr;
4171ae349f5Scvs2svn     cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id],
418503a7782SBrian Somers                      inet_ntoa(ipcp->my_ip));
4191ae349f5Scvs2svn   }
4201ae349f5Scvs2svn 
421503a7782SBrian Somers   if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
4221ae349f5Scvs2svn     const char *args;
4231ae349f5Scvs2svn     o.id = TY_COMPPROTO;
42483d1af55SBrian Somers     if (ipcp->heis1172) {
4251ae349f5Scvs2svn       o.len = 4;
4261ae349f5Scvs2svn       *(u_short *)o.data = htons(PROTO_VJCOMP);
4271ae349f5Scvs2svn       args = "";
4281ae349f5Scvs2svn     } else {
4291ae349f5Scvs2svn       o.len = 6;
430503a7782SBrian Somers       *(u_long *)o.data = htonl(ipcp->my_compproto);
431503a7782SBrian Somers       args = vj2asc(ipcp->my_compproto);
4321ae349f5Scvs2svn     }
4331ae349f5Scvs2svn     cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], args);
4341ae349f5Scvs2svn   }
43530c2f2ffSBrian Somers   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, buff, cp - buff);
4361ae349f5Scvs2svn }
4371ae349f5Scvs2svn 
4381ae349f5Scvs2svn static void
4391ae349f5Scvs2svn IpcpSendTerminateReq(struct fsm * fp)
4401ae349f5Scvs2svn {
4417308ec68SBrian Somers   /* Term REQ just sent by FSM */
4421ae349f5Scvs2svn }
4431ae349f5Scvs2svn 
4441ae349f5Scvs2svn static void
4451ae349f5Scvs2svn IpcpSendTerminateAck(struct fsm * fp)
4461ae349f5Scvs2svn {
4477308ec68SBrian Somers   /* Send Term ACK please */
4481ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpSendTerminateAck\n");
4491ae349f5Scvs2svn   FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
4501ae349f5Scvs2svn }
4511ae349f5Scvs2svn 
4521ae349f5Scvs2svn static void
4531ae349f5Scvs2svn IpcpLayerStart(struct fsm * fp)
4541ae349f5Scvs2svn {
4557308ec68SBrian Somers   /* We're about to start up ! */
4561ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerStart.\n");
457455aabc3SBrian Somers 
458455aabc3SBrian Somers   /* This is where we should be setting up the interface in AUTO mode */
4591ae349f5Scvs2svn }
4601ae349f5Scvs2svn 
4611ae349f5Scvs2svn static void
4621ae349f5Scvs2svn IpcpLayerFinish(struct fsm *fp)
4631ae349f5Scvs2svn {
4647308ec68SBrian Somers   /* We're now down */
4651ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerFinish.\n");
4661ae349f5Scvs2svn }
4671ae349f5Scvs2svn 
46868a0f0ccSBrian Somers void
46968a0f0ccSBrian Somers IpcpCleanInterface(struct fsm *fp)
47068a0f0ccSBrian Somers {
47168a0f0ccSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
47268a0f0ccSBrian Somers   struct ifaliasreq ifra;
47368a0f0ccSBrian Somers   struct sockaddr_in *me, *peer;
47468a0f0ccSBrian Somers   int s;
47568a0f0ccSBrian Somers 
47668a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
47768a0f0ccSBrian Somers   if (s < 0) {
47868a0f0ccSBrian Somers     LogPrintf(LogERROR, "IpcpCleanInterface: socket: %s\n", strerror(errno));
47968a0f0ccSBrian Somers     return;
48068a0f0ccSBrian Somers   }
48168a0f0ccSBrian Somers 
48268a0f0ccSBrian Somers   if (Enabled(ConfProxy))
483503a7782SBrian Somers     cifproxyarp(fp->bundle, ipcp->peer_ifip, s);
48468a0f0ccSBrian Somers 
485503a7782SBrian Somers   if (ipcp->my_ifip.s_addr != INADDR_ANY ||
486503a7782SBrian Somers       ipcp->peer_ifip.s_addr != INADDR_ANY) {
48768a0f0ccSBrian Somers     memset(&ifra, '\0', sizeof ifra);
48868a0f0ccSBrian Somers     strncpy(ifra.ifra_name, fp->bundle->ifname, sizeof ifra.ifra_name - 1);
48968a0f0ccSBrian Somers     ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
49068a0f0ccSBrian Somers     me = (struct sockaddr_in *)&ifra.ifra_addr;
49168a0f0ccSBrian Somers     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
49268a0f0ccSBrian Somers     me->sin_family = peer->sin_family = AF_INET;
49368a0f0ccSBrian Somers     me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
494503a7782SBrian Somers     me->sin_addr = ipcp->my_ifip;
495503a7782SBrian Somers     peer->sin_addr = ipcp->peer_ifip;
49668a0f0ccSBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
49768a0f0ccSBrian Somers       LogPrintf(LogERROR, "IpcpCleanInterface: ioctl(SIOCDIFADDR): %s\n",
49868a0f0ccSBrian Somers                 strerror(errno));
49968a0f0ccSBrian Somers       close(s);
50068a0f0ccSBrian Somers     }
501503a7782SBrian Somers     ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY;
50268a0f0ccSBrian Somers   }
50368a0f0ccSBrian Somers 
50468a0f0ccSBrian Somers   close(s);
50568a0f0ccSBrian Somers }
50668a0f0ccSBrian Somers 
5071ae349f5Scvs2svn static void
5081ae349f5Scvs2svn IpcpLayerDown(struct fsm *fp)
5091ae349f5Scvs2svn {
5107308ec68SBrian Somers   /* About to come down */
511aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
512455aabc3SBrian Somers   const char *s;
513455aabc3SBrian Somers 
514503a7782SBrian Somers   s = inet_ntoa(ipcp->peer_ifip);
515455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerDown: %s\n", s);
516455aabc3SBrian Somers 
51783d1af55SBrian Somers   throughput_stop(&ipcp->throughput);
51883d1af55SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
519455aabc3SBrian Somers   /*
520455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
521455aabc3SBrian Somers    * associate executable sections in files with events.
522455aabc3SBrian Somers    */
523455aabc3SBrian Somers   if (SelectSystem(fp->bundle, s, LINKDOWNFILE) < 0)
524455aabc3SBrian Somers     if (GetLabel()) {
525455aabc3SBrian Somers        if (SelectSystem(fp->bundle, GetLabel(), LINKDOWNFILE) < 0)
526455aabc3SBrian Somers        SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE);
527455aabc3SBrian Somers     } else
528455aabc3SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE);
529455aabc3SBrian Somers 
53068a0f0ccSBrian Somers   if (!(mode & MODE_AUTO))
53168a0f0ccSBrian Somers     IpcpCleanInterface(fp);
5321ae349f5Scvs2svn }
5331ae349f5Scvs2svn 
5341ae349f5Scvs2svn static void
5351ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp)
5361ae349f5Scvs2svn {
5377308ec68SBrian Somers   /* We're now up */
538aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
5391ae349f5Scvs2svn   char tbuff[100];
5401ae349f5Scvs2svn 
5411ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state);
542503a7782SBrian Somers   snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
543455aabc3SBrian Somers   LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n",
544503a7782SBrian Somers 	    tbuff, inet_ntoa(ipcp->peer_ip));
5451ae349f5Scvs2svn 
546503a7782SBrian Somers   if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
547eaa4df37SBrian Somers     sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
5481ae349f5Scvs2svn 
54930c2f2ffSBrian Somers   if (ipcp_SetIPaddress(fp->bundle, ipcp->my_ip,
55030c2f2ffSBrian Somers                         ipcp->peer_ip, 0) < 0) {
5511ae349f5Scvs2svn     LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
5521ae349f5Scvs2svn     return;
5531ae349f5Scvs2svn   }
554455aabc3SBrian Somers 
5551ae349f5Scvs2svn #ifndef NOALIAS
5561ae349f5Scvs2svn   if (mode & MODE_ALIAS)
557503a7782SBrian Somers     VarPacketAliasSetAddress(ipcp->my_ip);
5581ae349f5Scvs2svn #endif
559455aabc3SBrian Somers 
560455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerUp: %s\n",
561503a7782SBrian Somers             inet_ntoa(ipcp->peer_ifip));
562455aabc3SBrian Somers 
563455aabc3SBrian Somers   /*
564455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
565455aabc3SBrian Somers    * associate executable sections in files with events.
566455aabc3SBrian Somers    */
567503a7782SBrian Somers   if (SelectSystem(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE) < 0)
568455aabc3SBrian Somers     if (GetLabel()) {
569455aabc3SBrian Somers       if (SelectSystem(fp->bundle, GetLabel(), LINKUPFILE) < 0)
570455aabc3SBrian Somers         SelectSystem(fp->bundle, "MYADDR", LINKUPFILE);
571455aabc3SBrian Somers     } else
572455aabc3SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKUPFILE);
573455aabc3SBrian Somers 
57483d1af55SBrian Somers   throughput_start(&ipcp->throughput);
57585b542cfSBrian Somers   prompt_Display(&prompt, fp->bundle);
5761ae349f5Scvs2svn }
5771ae349f5Scvs2svn 
5781ae349f5Scvs2svn static int
5791ae349f5Scvs2svn AcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
5801ae349f5Scvs2svn {
5817308ec68SBrian Somers   /* Is the given IP in the given range ? */
5821ae349f5Scvs2svn   LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr));
5831ae349f5Scvs2svn   LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr));
5841ae349f5Scvs2svn   LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr));
5851ae349f5Scvs2svn   LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange->
5861ae349f5Scvs2svn 		  mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr));
5871ae349f5Scvs2svn   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
5881ae349f5Scvs2svn     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
5891ae349f5Scvs2svn }
5901ae349f5Scvs2svn 
5911ae349f5Scvs2svn static void
59230c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
59330c2f2ffSBrian Somers                  struct fsm_decode *dec)
5941ae349f5Scvs2svn {
5957308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
596aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
5971ae349f5Scvs2svn   int type, length;
5981ae349f5Scvs2svn   u_long *lp, compproto;
5991ae349f5Scvs2svn   struct compreq *pcomp;
6001ae349f5Scvs2svn   struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
60130c2f2ffSBrian Somers   char tbuff[100], tbuff2[100];
6021ae349f5Scvs2svn 
6031ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
6041ae349f5Scvs2svn     type = *cp;
6051ae349f5Scvs2svn     length = cp[1];
6061ae349f5Scvs2svn     if (type < NCFTYPES)
6071ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
6081ae349f5Scvs2svn     else if (type > 128 && type < 128 + NCFTYPES128)
6091ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
6101ae349f5Scvs2svn     else
6111ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
6121ae349f5Scvs2svn 
6131ae349f5Scvs2svn     switch (type) {
6141ae349f5Scvs2svn     case TY_IPADDR:		/* RFC1332 */
6151ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6161ae349f5Scvs2svn       ipaddr.s_addr = *lp;
6171ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
6181ae349f5Scvs2svn 
6191ae349f5Scvs2svn       switch (mode_type) {
6201ae349f5Scvs2svn       case MODE_REQ:
621503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
6221ae349f5Scvs2svn           if (ipaddr.s_addr == INADDR_ANY ||
623503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
62430c2f2ffSBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
62530c2f2ffSBrian Somers                                 ipaddr, 1)) {
6261ae349f5Scvs2svn             LogPrintf(LogIPCP, "%s: Address invalid or already in use\n",
6271ae349f5Scvs2svn                       inet_ntoa(ipaddr));
628503a7782SBrian Somers             ipcp->peer_ip = ChooseHisAddr
62930c2f2ffSBrian Somers               (fp->bundle, ipcp->cfg.my_range.ipaddr);
630503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
63130c2f2ffSBrian Somers 	      memcpy(dec->rejend, cp, length);
63230c2f2ffSBrian Somers 	      dec->rejend += length;
6331ae349f5Scvs2svn             } else {
63430c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
63530c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
63630c2f2ffSBrian Somers 	      dec->nakend += length;
6371ae349f5Scvs2svn             }
6381ae349f5Scvs2svn 	    break;
6391ae349f5Scvs2svn           }
640503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
6411ae349f5Scvs2svn 	  /*
6421ae349f5Scvs2svn 	   * If destination address is not acceptable, insist to use what we
6431ae349f5Scvs2svn 	   * want to use.
6441ae349f5Scvs2svn 	   */
64530c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
64630c2f2ffSBrian Somers 	  memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
64730c2f2ffSBrian Somers 	  dec->nakend += length;
6481ae349f5Scvs2svn 	  break;
6491ae349f5Scvs2svn 	}
650503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
65130c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
65230c2f2ffSBrian Somers 	dec->ackend += length;
6531ae349f5Scvs2svn 	break;
6541ae349f5Scvs2svn       case MODE_NAK:
655503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
6561ae349f5Scvs2svn 	  /* Use address suggested by peer */
6571ae349f5Scvs2svn 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
658503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
6591ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
660503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
6611ae349f5Scvs2svn 	} else {
6621ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
66383d1af55SBrian Somers           FsmClose(&ipcp->fsm);
6641ae349f5Scvs2svn 	}
6651ae349f5Scvs2svn 	break;
6661ae349f5Scvs2svn       case MODE_REJ:
667503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
6681ae349f5Scvs2svn 	break;
6691ae349f5Scvs2svn       }
6701ae349f5Scvs2svn       break;
6711ae349f5Scvs2svn     case TY_COMPPROTO:
6721ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
6731ae349f5Scvs2svn       compproto = htonl(*lp);
6741ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
6751ae349f5Scvs2svn 
6761ae349f5Scvs2svn       switch (mode_type) {
6771ae349f5Scvs2svn       case MODE_REQ:
6781ae349f5Scvs2svn 	if (!Acceptable(ConfVjcomp)) {
67930c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
68030c2f2ffSBrian Somers 	  dec->rejend += length;
6811ae349f5Scvs2svn 	} else {
6821ae349f5Scvs2svn 	  pcomp = (struct compreq *) (cp + 2);
6831ae349f5Scvs2svn 	  switch (length) {
6841ae349f5Scvs2svn 	  case 4:		/* RFC1172 */
6851ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
6861ae349f5Scvs2svn 	      LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
68783d1af55SBrian Somers 	      ipcp->heis1172 = 1;
688503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
68930c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
69030c2f2ffSBrian Somers 	      dec->ackend += length;
6911ae349f5Scvs2svn 	    } else {
69230c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
6931ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
69430c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, 2);
69530c2f2ffSBrian Somers 	      dec->nakend += length;
6961ae349f5Scvs2svn 	    }
6971ae349f5Scvs2svn 	    break;
6981ae349f5Scvs2svn 	  case 6:		/* RFC1332 */
6991ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
700503a7782SBrian Somers 		&& pcomp->slots <= MAX_VJ_STATES
701503a7782SBrian Somers                 && pcomp->slots >= MIN_VJ_STATES) {
702503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
70383d1af55SBrian Somers 	      ipcp->heis1172 = 0;
70430c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
70530c2f2ffSBrian Somers 	      dec->ackend += length;
7061ae349f5Scvs2svn 	    } else {
70730c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
7081ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
709503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
7101ae349f5Scvs2svn 	      pcomp->compcid = 0;
71130c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
71230c2f2ffSBrian Somers 	      dec->nakend += length;
7131ae349f5Scvs2svn 	    }
7141ae349f5Scvs2svn 	    break;
7151ae349f5Scvs2svn 	  default:
71630c2f2ffSBrian Somers 	    memcpy(dec->rejend, cp, length);
71730c2f2ffSBrian Somers 	    dec->rejend += length;
7181ae349f5Scvs2svn 	    break;
7191ae349f5Scvs2svn 	  }
7201ae349f5Scvs2svn 	}
7211ae349f5Scvs2svn 	break;
7221ae349f5Scvs2svn       case MODE_NAK:
7231ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
724503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
725503a7782SBrian Somers 	ipcp->my_compproto = compproto;
7261ae349f5Scvs2svn 	break;
7271ae349f5Scvs2svn       case MODE_REJ:
728503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
7291ae349f5Scvs2svn 	break;
7301ae349f5Scvs2svn       }
7311ae349f5Scvs2svn       break;
7321ae349f5Scvs2svn     case TY_IPADDRS:		/* RFC1172 */
7331ae349f5Scvs2svn       lp = (u_long *) (cp + 2);
7341ae349f5Scvs2svn       ipaddr.s_addr = *lp;
7351ae349f5Scvs2svn       lp = (u_long *) (cp + 6);
7361ae349f5Scvs2svn       dstipaddr.s_addr = *lp;
7371ae349f5Scvs2svn       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
7381ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
7391ae349f5Scvs2svn 
7401ae349f5Scvs2svn       switch (mode_type) {
7411ae349f5Scvs2svn       case MODE_REQ:
742503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
743503a7782SBrian Somers 	ipcp->my_ip = dstipaddr;
74430c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
74530c2f2ffSBrian Somers 	dec->ackend += length;
7461ae349f5Scvs2svn 	break;
7471ae349f5Scvs2svn       case MODE_NAK:
7481ae349f5Scvs2svn         snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
749503a7782SBrian Somers 		 inet_ntoa(ipcp->my_ip));
7501ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
751503a7782SBrian Somers 	ipcp->my_ip = ipaddr;
752503a7782SBrian Somers 	ipcp->peer_ip = dstipaddr;
7531ae349f5Scvs2svn 	break;
7541ae349f5Scvs2svn       case MODE_REJ:
755503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
7561ae349f5Scvs2svn 	break;
7571ae349f5Scvs2svn       }
7581ae349f5Scvs2svn       break;
7591ae349f5Scvs2svn 
7601ae349f5Scvs2svn       /*
7611ae349f5Scvs2svn        * MS extensions for MS's PPP
7621ae349f5Scvs2svn        */
7631ae349f5Scvs2svn 
7641ae349f5Scvs2svn #ifndef NOMSEXT
7651ae349f5Scvs2svn     case TY_PRIMARY_DNS:	/* MS PPP DNS negotiation hack */
7661ae349f5Scvs2svn     case TY_SECONDARY_DNS:
76730c2f2ffSBrian Somers       switch (mode_type) {
76830c2f2ffSBrian Somers       case MODE_REQ:
7691ae349f5Scvs2svn         if (!Enabled(ConfMSExt)) {
7701ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n");
77183d1af55SBrian Somers 	  ipcp->my_reject |= (1 << type);
77230c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
77330c2f2ffSBrian Somers 	  dec->rejend += length;
7741ae349f5Scvs2svn 	  break;
7751ae349f5Scvs2svn         }
7761ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
7771ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
778503a7782SBrian Somers 	ms_info_req.s_addr = ipcp->cfg.ns_entries
77929e275ceSBrian Somers           [(type - TY_PRIMARY_DNS) ? 1 : 0].s_addr;
7801ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
7811ae349f5Scvs2svn 
7821ae349f5Scvs2svn 	  /*
7831ae349f5Scvs2svn 	   * So the client has got the DNS stuff wrong (first request) so
7841ae349f5Scvs2svn 	   * we'll tell 'em how it is
7851ae349f5Scvs2svn 	   */
78630c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
7871ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n",
7881ae349f5Scvs2svn 		    type,
7891ae349f5Scvs2svn 		    inet_ntoa(dnsstuff),
7901ae349f5Scvs2svn 		    inet_ntoa(ms_info_req));
79130c2f2ffSBrian Somers 	  memcpy(dec->nakend+2, &ms_info_req, length);
79230c2f2ffSBrian Somers 	  dec->nakend += length;
7931ae349f5Scvs2svn 	  break;
7941ae349f5Scvs2svn 	}
7951ae349f5Scvs2svn 
7961ae349f5Scvs2svn 	/*
7971ae349f5Scvs2svn 	 * Otherwise they have it right (this time) so we send a ack packet
7981ae349f5Scvs2svn 	 * back confirming it... end of story
7991ae349f5Scvs2svn 	 */
8001ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n",
8011ae349f5Scvs2svn 		  type,
8021ae349f5Scvs2svn 		  inet_ntoa(ms_info_req));
80330c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
80430c2f2ffSBrian Somers 	dec->ackend += length;
8051ae349f5Scvs2svn 	break;
8061ae349f5Scvs2svn       case MODE_NAK:		/* what does this mean?? */
8071ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type);
8081ae349f5Scvs2svn 	break;
8091ae349f5Scvs2svn       case MODE_REJ:		/* confused?? me to :) */
8101ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type);
8111ae349f5Scvs2svn 	break;
8121ae349f5Scvs2svn       }
8131ae349f5Scvs2svn       break;
8141ae349f5Scvs2svn 
8151ae349f5Scvs2svn     case TY_PRIMARY_NBNS:	/* MS PPP NetBIOS nameserver hack */
8161ae349f5Scvs2svn     case TY_SECONDARY_NBNS:
81730c2f2ffSBrian Somers       switch (mode_type) {
81830c2f2ffSBrian Somers       case MODE_REQ:
8191ae349f5Scvs2svn         if (!Enabled(ConfMSExt)) {
8201ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n");
82183d1af55SBrian Somers 	  ipcp->my_reject |= (1 << type);
82230c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
82330c2f2ffSBrian Somers 	  dec->rejend += length;
8241ae349f5Scvs2svn 	  break;
8251ae349f5Scvs2svn         }
8261ae349f5Scvs2svn 	lp = (u_long *) (cp + 2);
8271ae349f5Scvs2svn 	dnsstuff.s_addr = *lp;
828503a7782SBrian Somers 	ms_info_req.s_addr = ipcp->cfg.nbns_entries
82929e275ceSBrian Somers           [(type - TY_PRIMARY_NBNS) ? 1 : 0].s_addr;
8301ae349f5Scvs2svn 	if (dnsstuff.s_addr != ms_info_req.s_addr) {
83130c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
83230c2f2ffSBrian Somers 	  memcpy(dec->nakend+2, &ms_info_req.s_addr, length);
8331ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n",
8341ae349f5Scvs2svn 		    type,
8351ae349f5Scvs2svn 		    inet_ntoa(dnsstuff),
8361ae349f5Scvs2svn 		    inet_ntoa(ms_info_req));
83730c2f2ffSBrian Somers 	  dec->nakend += length;
8381ae349f5Scvs2svn 	  break;
8391ae349f5Scvs2svn 	}
8401ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n",
8411ae349f5Scvs2svn 		  type,
8421ae349f5Scvs2svn 		  inet_ntoa(ms_info_req));
84330c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
84430c2f2ffSBrian Somers 	dec->ackend += length;
8451ae349f5Scvs2svn 	break;
8461ae349f5Scvs2svn       case MODE_NAK:
8471ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
8481ae349f5Scvs2svn 	break;
8491ae349f5Scvs2svn       case MODE_REJ:
8501ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
8511ae349f5Scvs2svn 	break;
8521ae349f5Scvs2svn       }
8531ae349f5Scvs2svn       break;
8541ae349f5Scvs2svn 
8551ae349f5Scvs2svn #endif
8561ae349f5Scvs2svn 
8571ae349f5Scvs2svn     default:
85830c2f2ffSBrian Somers       if (mode_type != MODE_NOP) {
85983d1af55SBrian Somers         ipcp->my_reject |= (1 << type);
86030c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
86130c2f2ffSBrian Somers         dec->rejend += length;
86230c2f2ffSBrian Somers       }
8631ae349f5Scvs2svn       break;
8641ae349f5Scvs2svn     }
8651ae349f5Scvs2svn     plen -= length;
8661ae349f5Scvs2svn     cp += length;
8671ae349f5Scvs2svn   }
8681ae349f5Scvs2svn }
8691ae349f5Scvs2svn 
8701ae349f5Scvs2svn void
8715828db6dSBrian Somers IpcpInput(struct ipcp *ipcp, struct mbuf * bp)
8721ae349f5Scvs2svn {
8737308ec68SBrian Somers   /* Got PROTO_IPCP from link */
8745828db6dSBrian Somers   FsmInput(&ipcp->fsm, bp);
8751ae349f5Scvs2svn }
8761ae349f5Scvs2svn 
8771ae349f5Scvs2svn int
8787a6f8720SBrian Somers UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
8791ae349f5Scvs2svn {
8805828db6dSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
8815828db6dSBrian Somers 
8827308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
8835828db6dSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
8845828db6dSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
8851ae349f5Scvs2svn   if (strpbrk(hisaddr, ",-")) {
8865828db6dSBrian Somers     iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
8875828db6dSBrian Somers     if (iplist_isvalid(&ipcp->cfg.peer_list)) {
8885828db6dSBrian Somers       iplist_setrandpos(&ipcp->cfg.peer_list);
88930c2f2ffSBrian Somers       ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
8905828db6dSBrian Somers       if (ipcp->peer_ip.s_addr == INADDR_ANY) {
8915828db6dSBrian Somers         LogPrintf(LogWARN, "%s: None available !\n",
8925828db6dSBrian Somers                   ipcp->cfg.peer_list.src);
8931ae349f5Scvs2svn         return(0);
8941ae349f5Scvs2svn       }
8955828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
8965828db6dSBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
8975828db6dSBrian Somers       ipcp->cfg.peer_range.width = 32;
8981ae349f5Scvs2svn     } else {
8991ae349f5Scvs2svn       LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr);
9001ae349f5Scvs2svn       return 0;
9011ae349f5Scvs2svn     }
9025828db6dSBrian Somers   } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr,
9035828db6dSBrian Somers 		       &ipcp->cfg.peer_range.mask,
9045828db6dSBrian Somers                        &ipcp->cfg.peer_range.width) != 0) {
9055828db6dSBrian Somers     ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
9061ae349f5Scvs2svn 
90730c2f2ffSBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
90830c2f2ffSBrian Somers                                      ipcp->cfg.peer_range.ipaddr, 0) < 0) {
9095828db6dSBrian Somers       ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
9105828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
9111ae349f5Scvs2svn       return 0;
9121ae349f5Scvs2svn     }
9131ae349f5Scvs2svn   } else
9141ae349f5Scvs2svn     return 0;
9151ae349f5Scvs2svn 
9161ae349f5Scvs2svn   return 1;
9171ae349f5Scvs2svn }
918