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 * 20641684cdSBrian Somers * $Id: ipcp.c,v 1.50.2.53 1998/05/19 21:51:21 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 <net/if.h> 33455aabc3SBrian Somers #include <sys/sockio.h> 341fa665f5SBrian Somers #include <sys/un.h> 351ae349f5Scvs2svn 363edeb0c6SBrian Somers #include <fcntl.h> 373edeb0c6SBrian Somers #include <resolv.h> 381ae349f5Scvs2svn #include <stdlib.h> 391ae349f5Scvs2svn #include <string.h> 40455aabc3SBrian Somers #include <sys/errno.h> 416140ba11SBrian Somers #include <termios.h> 421ae349f5Scvs2svn #include <unistd.h> 431ae349f5Scvs2svn 441ae349f5Scvs2svn #include "command.h" 451ae349f5Scvs2svn #include "mbuf.h" 461ae349f5Scvs2svn #include "log.h" 471ae349f5Scvs2svn #include "defs.h" 481ae349f5Scvs2svn #include "timer.h" 491ae349f5Scvs2svn #include "fsm.h" 501ae349f5Scvs2svn #include "lcpproto.h" 511ae349f5Scvs2svn #include "lcp.h" 521ae349f5Scvs2svn #include "iplist.h" 5329e275ceSBrian Somers #include "throughput.h" 541ae349f5Scvs2svn #include "slcompress.h" 55eaa4df37SBrian Somers #include "ipcp.h" 565ca5389aSBrian Somers #include "filter.h" 572f786681SBrian Somers #include "descriptor.h" 581ae349f5Scvs2svn #include "loadalias.h" 591ae349f5Scvs2svn #include "vjcomp.h" 60879ed6faSBrian Somers #include "lqr.h" 618c07a7b2SBrian Somers #include "hdlc.h" 626140ba11SBrian Somers #include "async.h" 633b0f8d2eSBrian Somers #include "ccp.h" 648c07a7b2SBrian Somers #include "link.h" 6563b73463SBrian Somers #include "physical.h" 663b0f8d2eSBrian Somers #include "mp.h" 673b0f8d2eSBrian Somers #include "bundle.h" 68455aabc3SBrian Somers #include "id.h" 69455aabc3SBrian Somers #include "arp.h" 70455aabc3SBrian Somers #include "systems.h" 7185b542cfSBrian Somers #include "prompt.h" 72610b185fSBrian Somers #include "route.h" 731ae349f5Scvs2svn 74503a7782SBrian Somers #undef REJECTED 75503a7782SBrian Somers #define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) 763edeb0c6SBrian Somers #define issep(ch) ((ch) == ' ' || (ch) == '\t') 773edeb0c6SBrian Somers #define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.') 78503a7782SBrian Somers 7929e275ceSBrian Somers struct compreq { 8029e275ceSBrian Somers u_short proto; 8129e275ceSBrian Somers u_char slots; 8229e275ceSBrian Somers u_char compcid; 8329e275ceSBrian Somers }; 841ae349f5Scvs2svn 856f384573SBrian Somers static int IpcpLayerUp(struct fsm *); 861ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *); 877308ec68SBrian Somers static void IpcpLayerStart(struct fsm *); 887308ec68SBrian Somers static void IpcpLayerFinish(struct fsm *); 891ae349f5Scvs2svn static void IpcpInitRestartCounter(struct fsm *); 907308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *); 912267893fSBrian Somers static void IpcpSentTerminateReq(struct fsm *); 922267893fSBrian Somers static void IpcpSendTerminateAck(struct fsm *, u_char); 9330c2f2ffSBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int, 9430c2f2ffSBrian Somers struct fsm_decode *); 9583d1af55SBrian Somers 9683d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = { 9783d1af55SBrian Somers IpcpLayerUp, 9883d1af55SBrian Somers IpcpLayerDown, 9983d1af55SBrian Somers IpcpLayerStart, 1006d666775SBrian Somers IpcpLayerFinish, 10183d1af55SBrian Somers IpcpInitRestartCounter, 10283d1af55SBrian Somers IpcpSendConfigReq, 1032267893fSBrian Somers IpcpSentTerminateReq, 10483d1af55SBrian Somers IpcpSendTerminateAck, 10583d1af55SBrian Somers IpcpDecodeConfig, 106dd7e2610SBrian Somers fsm_NullRecvResetReq, 107dd7e2610SBrian Somers fsm_NullRecvResetAck 10883d1af55SBrian Somers }; 1091ae349f5Scvs2svn 1101ae349f5Scvs2svn static const char *cftypes[] = { 1111ae349f5Scvs2svn /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 1121ae349f5Scvs2svn "???", 1131ae349f5Scvs2svn "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ 1141ae349f5Scvs2svn "COMPPROTO", /* 2: IP-Compression-Protocol */ 1151ae349f5Scvs2svn "IPADDR", /* 3: IP-Address */ 1161ae349f5Scvs2svn }; 1171ae349f5Scvs2svn 1181ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 1191ae349f5Scvs2svn 1201ae349f5Scvs2svn static const char *cftypes128[] = { 1211ae349f5Scvs2svn /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 1221ae349f5Scvs2svn "???", 1231ae349f5Scvs2svn "PRIDNS", /* 129: Primary DNS Server Address */ 1241ae349f5Scvs2svn "PRINBNS", /* 130: Primary NBNS Server Address */ 1251ae349f5Scvs2svn "SECDNS", /* 131: Secondary DNS Server Address */ 1261ae349f5Scvs2svn "SECNBNS", /* 132: Secondary NBNS Server Address */ 1271ae349f5Scvs2svn }; 1281ae349f5Scvs2svn 1291ae349f5Scvs2svn #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) 1301ae349f5Scvs2svn 1311ae349f5Scvs2svn void 1325828db6dSBrian Somers ipcp_AddInOctets(struct ipcp *ipcp, int n) 1331ae349f5Scvs2svn { 1345828db6dSBrian Somers throughput_addin(&ipcp->throughput, n); 1351ae349f5Scvs2svn } 1361ae349f5Scvs2svn 1371ae349f5Scvs2svn void 1385828db6dSBrian Somers ipcp_AddOutOctets(struct ipcp *ipcp, int n) 1391ae349f5Scvs2svn { 1405828db6dSBrian Somers throughput_addout(&ipcp->throughput, n); 1411ae349f5Scvs2svn } 1421ae349f5Scvs2svn 1433edeb0c6SBrian Somers static void 1443edeb0c6SBrian Somers getdns(struct ipcp *ipcp, struct in_addr addr[2]) 1453edeb0c6SBrian Somers { 1463edeb0c6SBrian Somers FILE *fp; 1473edeb0c6SBrian Somers 1483edeb0c6SBrian Somers addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 1493edeb0c6SBrian Somers if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 1503edeb0c6SBrian Somers char buf[LINE_LEN], *cp, *end; 1513edeb0c6SBrian Somers int n; 1523edeb0c6SBrian Somers 1533edeb0c6SBrian Somers n = 0; 1543edeb0c6SBrian Somers buf[sizeof buf - 1] = '\0'; 1553edeb0c6SBrian Somers while (fgets(buf, sizeof buf - 1, fp)) { 1563edeb0c6SBrian Somers if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) { 1573edeb0c6SBrian Somers for (cp = buf + 11; issep(*cp); cp++) 1583edeb0c6SBrian Somers ; 1593edeb0c6SBrian Somers for (end = cp; isip(*end); end++) 1603edeb0c6SBrian Somers ; 1613edeb0c6SBrian Somers *end = '\0'; 1623edeb0c6SBrian Somers if (inet_aton(cp, addr+n) && ++n == 2) 1633edeb0c6SBrian Somers break; 1643edeb0c6SBrian Somers } 1653edeb0c6SBrian Somers } 1663edeb0c6SBrian Somers if (n == 1) 1673edeb0c6SBrian Somers addr[1] = addr[0]; 1683edeb0c6SBrian Somers fclose(fp); 1693edeb0c6SBrian Somers } 1703edeb0c6SBrian Somers } 1713edeb0c6SBrian Somers 1723edeb0c6SBrian Somers static int 1733edeb0c6SBrian Somers setdns(struct ipcp *ipcp, struct in_addr addr[2]) 1743edeb0c6SBrian Somers { 1753edeb0c6SBrian Somers FILE *fp; 1763edeb0c6SBrian Somers char wbuf[LINE_LEN + 54]; 1773edeb0c6SBrian Somers int wlen; 1783edeb0c6SBrian Somers 1793edeb0c6SBrian Somers if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) { 1803edeb0c6SBrian Somers struct in_addr old[2]; 1813edeb0c6SBrian Somers 1823edeb0c6SBrian Somers getdns(ipcp, old); 1833edeb0c6SBrian Somers if (addr[0].s_addr == INADDR_ANY) 1843edeb0c6SBrian Somers addr[0] = old[0]; 1853edeb0c6SBrian Somers if (addr[1].s_addr == INADDR_ANY) 1863edeb0c6SBrian Somers addr[1] = old[1]; 1873edeb0c6SBrian Somers } 1883edeb0c6SBrian Somers 1893edeb0c6SBrian Somers if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) { 190dd7e2610SBrian Somers log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n", 1913edeb0c6SBrian Somers _PATH_RESCONF); 1923edeb0c6SBrian Somers return 0; 1933edeb0c6SBrian Somers } 1943edeb0c6SBrian Somers 1953edeb0c6SBrian Somers wlen = 0; 1963edeb0c6SBrian Somers if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 1973edeb0c6SBrian Somers char buf[LINE_LEN]; 1983edeb0c6SBrian Somers int len; 1993edeb0c6SBrian Somers 2003edeb0c6SBrian Somers buf[sizeof buf - 1] = '\0'; 2013edeb0c6SBrian Somers while (fgets(buf, sizeof buf - 1, fp)) { 2023edeb0c6SBrian Somers if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) { 2033edeb0c6SBrian Somers len = strlen(buf); 2043edeb0c6SBrian Somers if (len > sizeof wbuf - wlen) { 205dd7e2610SBrian Somers log_Printf(LogWARN, "%s: Can only cope with max file size %d\n", 2063edeb0c6SBrian Somers _PATH_RESCONF, LINE_LEN); 2073edeb0c6SBrian Somers fclose(fp); 2083edeb0c6SBrian Somers return 0; 2093edeb0c6SBrian Somers } 2103edeb0c6SBrian Somers memcpy(wbuf + wlen, buf, len); 2113edeb0c6SBrian Somers wlen += len; 2123edeb0c6SBrian Somers } 2133edeb0c6SBrian Somers } 2143edeb0c6SBrian Somers fclose(fp); 2153edeb0c6SBrian Somers } 2163edeb0c6SBrian Somers 2173edeb0c6SBrian Somers if (addr[0].s_addr != INADDR_ANY) { 2183edeb0c6SBrian Somers snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 2193edeb0c6SBrian Somers inet_ntoa(addr[0])); 220dd7e2610SBrian Somers log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11); 2213edeb0c6SBrian Somers wlen += strlen(wbuf + wlen); 2223edeb0c6SBrian Somers } 2233edeb0c6SBrian Somers 2243edeb0c6SBrian Somers if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) { 2253edeb0c6SBrian Somers snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 2263edeb0c6SBrian Somers inet_ntoa(addr[1])); 227dd7e2610SBrian Somers log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11); 2283edeb0c6SBrian Somers wlen += strlen(wbuf + wlen); 2293edeb0c6SBrian Somers } 2303edeb0c6SBrian Somers 2313edeb0c6SBrian Somers if (wlen) { 2323edeb0c6SBrian Somers int fd; 2333edeb0c6SBrian Somers 2343edeb0c6SBrian Somers if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) { 2353edeb0c6SBrian Somers if (write(fd, wbuf, wlen) != wlen) { 236dd7e2610SBrian Somers log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno)); 2373edeb0c6SBrian Somers close(fd); 2383edeb0c6SBrian Somers return 0; 2393edeb0c6SBrian Somers } 2403edeb0c6SBrian Somers if (ftruncate(fd, wlen) == -1) { 241dd7e2610SBrian Somers log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno)); 2423edeb0c6SBrian Somers close(fd); 2433edeb0c6SBrian Somers return 0; 2443edeb0c6SBrian Somers } 2453edeb0c6SBrian Somers close(fd); 2463edeb0c6SBrian Somers } else { 247dd7e2610SBrian Somers log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno)); 2483edeb0c6SBrian Somers return 0; 2493edeb0c6SBrian Somers } 2503edeb0c6SBrian Somers } 2513edeb0c6SBrian Somers 2523edeb0c6SBrian Somers return 1; 2533edeb0c6SBrian Somers } 2543edeb0c6SBrian Somers 2551ae349f5Scvs2svn int 256dd7e2610SBrian Somers ipcp_Show(struct cmdargs const *arg) 2571ae349f5Scvs2svn { 258610b185fSBrian Somers struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 259610b185fSBrian Somers 260610b185fSBrian Somers prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, 261610b185fSBrian Somers State2Nam(ipcp->fsm.state)); 262610b185fSBrian Somers if (ipcp->fsm.state == ST_OPENED) { 263b6217683SBrian Somers prompt_Printf(arg->prompt, " His side: %s, %s\n", 264610b185fSBrian Somers inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); 265b6217683SBrian Somers prompt_Printf(arg->prompt, " My side: %s, %s\n", 266610b185fSBrian Somers inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); 267610b185fSBrian Somers } 268610b185fSBrian Somers 269610b185fSBrian Somers if (ipcp->route) { 270610b185fSBrian Somers prompt_Printf(arg->prompt, "\n"); 271610b185fSBrian Somers route_ShowSticky(arg->prompt, ipcp->route); 2721ae349f5Scvs2svn } 2731ae349f5Scvs2svn 274b6217683SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 27550abd4c8SBrian Somers prompt_Printf(arg->prompt, " My Address: %s/%d", 276610b185fSBrian Somers inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width); 27750abd4c8SBrian Somers 278610b185fSBrian Somers if (ipcp->cfg.HaveTriggerAddress) 27950abd4c8SBrian Somers prompt_Printf(arg->prompt, " (trigger with %s)", 280610b185fSBrian Somers inet_ntoa(ipcp->cfg.TriggerAddress)); 28150abd4c8SBrian Somers prompt_Printf(arg->prompt, "\n VJ compression: %s (%d slots %s slot " 282610b185fSBrian Somers "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), 283610b185fSBrian Somers ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); 28450abd4c8SBrian Somers 285610b185fSBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) 286b6217683SBrian Somers prompt_Printf(arg->prompt, " His Address: %s\n", 287610b185fSBrian Somers ipcp->cfg.peer_list.src); 2881ae349f5Scvs2svn else 289b6217683SBrian Somers prompt_Printf(arg->prompt, " His Address: %s/%d\n", 290610b185fSBrian Somers inet_ntoa(ipcp->cfg.peer_range.ipaddr), 291610b185fSBrian Somers ipcp->cfg.peer_range.width); 29250abd4c8SBrian Somers 2933edeb0c6SBrian Somers prompt_Printf(arg->prompt, " DNS: %s, ", 294610b185fSBrian Somers inet_ntoa(ipcp->cfg.ns.dns[0])); 295610b185fSBrian Somers prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]), 296610b185fSBrian Somers command_ShowNegval(ipcp->cfg.ns.dns_neg)); 2973edeb0c6SBrian Somers prompt_Printf(arg->prompt, " NetBIOS NS: %s, ", 298610b185fSBrian Somers inet_ntoa(ipcp->cfg.ns.nbns[0])); 299610b185fSBrian Somers prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1])); 3001342caedSBrian Somers 301b6217683SBrian Somers prompt_Printf(arg->prompt, "\n"); 302610b185fSBrian Somers throughput_disp(&ipcp->throughput, arg->prompt); 3031ae349f5Scvs2svn 3041ae349f5Scvs2svn return 0; 3051ae349f5Scvs2svn } 3061ae349f5Scvs2svn 3071ae349f5Scvs2svn int 308dd7e2610SBrian Somers ipcp_vjset(struct cmdargs const *arg) 3091ae349f5Scvs2svn { 31025092092SBrian Somers if (arg->argc != arg->argn+2) 3111ae349f5Scvs2svn return -1; 31225092092SBrian Somers if (!strcasecmp(arg->argv[arg->argn], "slots")) { 3131ae349f5Scvs2svn int slots; 3141ae349f5Scvs2svn 31525092092SBrian Somers slots = atoi(arg->argv[arg->argn+1]); 3161ae349f5Scvs2svn if (slots < 4 || slots > 16) 3171ae349f5Scvs2svn return 1; 3181342caedSBrian Somers arg->bundle->ncp.ipcp.cfg.vj.slots = slots; 3191ae349f5Scvs2svn return 0; 32025092092SBrian Somers } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { 32125092092SBrian Somers if (!strcasecmp(arg->argv[arg->argn+1], "on")) 3221342caedSBrian Somers arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; 32325092092SBrian Somers else if (!strcasecmp(arg->argv[arg->argn+1], "off")) 3241342caedSBrian Somers arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; 3251ae349f5Scvs2svn else 3261ae349f5Scvs2svn return 2; 3271ae349f5Scvs2svn return 0; 3281ae349f5Scvs2svn } 3291ae349f5Scvs2svn return -1; 3301ae349f5Scvs2svn } 3311ae349f5Scvs2svn 3321ae349f5Scvs2svn void 3336d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, 3346d666775SBrian Somers const struct fsm_parent *parent) 3351ae349f5Scvs2svn { 336503a7782SBrian Somers struct hostent *hp; 337503a7782SBrian Somers char name[MAXHOSTNAMELEN]; 3383b0f8d2eSBrian Somers static const char *timer_names[] = 3393b0f8d2eSBrian Somers {"IPCP restart", "IPCP openmode", "IPCP stopped"}; 34029e275ceSBrian Somers 3413b0f8d2eSBrian Somers fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP, 3423b0f8d2eSBrian Somers bundle, l, parent, &ipcp_Callbacks, timer_names); 343503a7782SBrian Somers 344610b185fSBrian Somers ipcp->route = NULL; 3451342caedSBrian Somers ipcp->cfg.vj.slots = DEF_VJ_STATES; 3461342caedSBrian Somers ipcp->cfg.vj.slotcomp = 1; 347503a7782SBrian Somers memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 348503a7782SBrian Somers if (gethostname(name, sizeof name) == 0) { 349503a7782SBrian Somers hp = gethostbyname(name); 350503a7782SBrian Somers if (hp && hp->h_addrtype == AF_INET) { 351503a7782SBrian Somers memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); 352503a7782SBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 353503a7782SBrian Somers ipcp->cfg.peer_range.width = 32; 3541ae349f5Scvs2svn } 355503a7782SBrian Somers } 35630c2f2ffSBrian Somers ipcp->cfg.netmask.s_addr = INADDR_ANY; 357503a7782SBrian Somers memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 358503a7782SBrian Somers iplist_setsrc(&ipcp->cfg.peer_list, ""); 359503a7782SBrian Somers ipcp->cfg.HaveTriggerAddress = 0; 360503a7782SBrian Somers 3613edeb0c6SBrian Somers ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY; 3623edeb0c6SBrian Somers ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY; 3633edeb0c6SBrian Somers ipcp->cfg.ns.dns_neg = 0; 3643edeb0c6SBrian Somers ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; 3653edeb0c6SBrian Somers ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; 366cd9647a1SBrian Somers 367cd9647a1SBrian Somers ipcp->cfg.fsmretry = DEF_FSMRETRY; 3681342caedSBrian Somers ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; 369503a7782SBrian Somers 370eaa4df37SBrian Somers memset(&ipcp->vj, '\0', sizeof ipcp->vj); 371eaa4df37SBrian Somers 372503a7782SBrian Somers ipcp->my_ifip.s_addr = INADDR_ANY; 373503a7782SBrian Somers ipcp->peer_ifip.s_addr = INADDR_ANY; 374503a7782SBrian Somers 375fdf61171SBrian Somers throughput_init(&ipcp->throughput); 376503a7782SBrian Somers ipcp_Setup(ipcp); 377503a7782SBrian Somers } 378503a7782SBrian Somers 379503a7782SBrian Somers void 380ce828a6eSBrian Somers ipcp_SetLink(struct ipcp *ipcp, struct link *l) 381ce828a6eSBrian Somers { 382ce828a6eSBrian Somers ipcp->fsm.link = l; 383ce828a6eSBrian Somers } 384ce828a6eSBrian Somers 385ce828a6eSBrian Somers void 386503a7782SBrian Somers ipcp_Setup(struct ipcp *ipcp) 387503a7782SBrian Somers { 388503a7782SBrian Somers int pos; 389503a7782SBrian Somers 390503a7782SBrian Somers ipcp->fsm.open_mode = 0; 3915454ccd9SBrian Somers ipcp->fsm.maxconfig = 10; 392503a7782SBrian Somers 393503a7782SBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 394503a7782SBrian Somers if (ipcp->my_ifip.s_addr != INADDR_ANY && 395503a7782SBrian Somers (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1) 396503a7782SBrian Somers ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos); 397503a7782SBrian Somers else 398503a7782SBrian Somers ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); 399503a7782SBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 400503a7782SBrian Somers ipcp->cfg.peer_range.width = 32; 401503a7782SBrian Somers } 402503a7782SBrian Somers 403503a7782SBrian Somers ipcp->heis1172 = 0; 404503a7782SBrian Somers 405503a7782SBrian Somers ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; 406503a7782SBrian Somers ipcp->peer_compproto = 0; 4071ae349f5Scvs2svn 4088390b576SBrian Somers if (ipcp->cfg.HaveTriggerAddress) { 4091ae349f5Scvs2svn /* 4101ae349f5Scvs2svn * Some implementations of PPP require that we send a 4111ae349f5Scvs2svn * *special* value as our address, even though the rfc specifies 4121ae349f5Scvs2svn * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 4131ae349f5Scvs2svn */ 414503a7782SBrian Somers ipcp->my_ip = ipcp->cfg.TriggerAddress; 415dd7e2610SBrian Somers log_Printf(LogIPCP, "Using trigger address %s\n", 416503a7782SBrian Somers inet_ntoa(ipcp->cfg.TriggerAddress)); 4178390b576SBrian Somers } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) == 4188390b576SBrian Somers (ipcp->cfg.my_range.ipaddr.s_addr & 4198390b576SBrian Somers ipcp->cfg.my_range.mask.s_addr)) 4208390b576SBrian Somers /* 4218390b576SBrian Somers * Otherwise, if we've been assigned an IP number before, we really 4228390b576SBrian Somers * want to keep the same IP number so that we can keep any existing 4238390b576SBrian Somers * connections that are bound to that IP. 4248390b576SBrian Somers */ 4258390b576SBrian Somers ipcp->my_ip = ipcp->my_ifip; 4268390b576SBrian Somers else 427503a7782SBrian Somers ipcp->my_ip = ipcp->cfg.my_range.ipaddr; 42829e275ceSBrian Somers 4291342caedSBrian Somers if (IsEnabled(ipcp->cfg.vj.neg)) 430503a7782SBrian Somers ipcp->my_compproto = (PROTO_VJCOMP << 16) + 4311342caedSBrian Somers ((ipcp->cfg.vj.slots - 1) << 8) + 4321342caedSBrian Somers ipcp->cfg.vj.slotcomp; 4331ae349f5Scvs2svn else 434503a7782SBrian Somers ipcp->my_compproto = 0; 4351342caedSBrian Somers sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); 43629e275ceSBrian Somers 437503a7782SBrian Somers ipcp->peer_reject = 0; 438503a7782SBrian Somers ipcp->my_reject = 0; 439503a7782SBrian Somers 440fdf61171SBrian Somers throughput_stop(&ipcp->throughput); 441503a7782SBrian Somers throughput_init(&ipcp->throughput); 4421ae349f5Scvs2svn } 4431ae349f5Scvs2svn 444455aabc3SBrian Somers static int 44530c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, 44630c2f2ffSBrian Somers struct in_addr hisaddr, int silent) 447455aabc3SBrian Somers { 448455aabc3SBrian Somers struct sockaddr_in *sock_in; 449455aabc3SBrian Somers int s; 450455aabc3SBrian Somers u_long mask, addr; 451455aabc3SBrian Somers struct ifaliasreq ifra; 452455aabc3SBrian Somers 453455aabc3SBrian Somers /* If given addresses are alreay set, then ignore this request */ 45430c2f2ffSBrian Somers if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr && 45530c2f2ffSBrian Somers bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr) 456455aabc3SBrian Somers return 0; 457455aabc3SBrian Somers 458dd7e2610SBrian Somers ipcp_CleanInterface(&bundle->ncp.ipcp); 45968a0f0ccSBrian Somers 460455aabc3SBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 461455aabc3SBrian Somers if (s < 0) { 462dd7e2610SBrian Somers log_Printf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno)); 463455aabc3SBrian Somers return (-1); 464455aabc3SBrian Somers } 465455aabc3SBrian Somers 466455aabc3SBrian Somers memset(&ifra, '\0', sizeof ifra); 467faefde08SBrian Somers strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1); 468455aabc3SBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 469455aabc3SBrian Somers 470455aabc3SBrian Somers /* Set interface address */ 471455aabc3SBrian Somers sock_in = (struct sockaddr_in *)&ifra.ifra_addr; 472455aabc3SBrian Somers sock_in->sin_family = AF_INET; 473455aabc3SBrian Somers sock_in->sin_addr = myaddr; 474455aabc3SBrian Somers sock_in->sin_len = sizeof *sock_in; 475455aabc3SBrian Somers 476455aabc3SBrian Somers /* Set destination address */ 477455aabc3SBrian Somers sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr; 478455aabc3SBrian Somers sock_in->sin_family = AF_INET; 479455aabc3SBrian Somers sock_in->sin_addr = hisaddr; 480455aabc3SBrian Somers sock_in->sin_len = sizeof *sock_in; 481455aabc3SBrian Somers 482455aabc3SBrian Somers addr = ntohl(myaddr.s_addr); 483455aabc3SBrian Somers if (IN_CLASSA(addr)) 484455aabc3SBrian Somers mask = IN_CLASSA_NET; 485455aabc3SBrian Somers else if (IN_CLASSB(addr)) 486455aabc3SBrian Somers mask = IN_CLASSB_NET; 487455aabc3SBrian Somers else 488455aabc3SBrian Somers mask = IN_CLASSC_NET; 489455aabc3SBrian Somers 490455aabc3SBrian Somers /* if subnet mask is given, use it instead of class mask */ 49130c2f2ffSBrian Somers if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY && 49230c2f2ffSBrian Somers (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask) 49330c2f2ffSBrian Somers mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr); 494455aabc3SBrian Somers 495455aabc3SBrian Somers sock_in = (struct sockaddr_in *)&ifra.ifra_mask; 496455aabc3SBrian Somers sock_in->sin_family = AF_INET; 497455aabc3SBrian Somers sock_in->sin_addr.s_addr = htonl(mask); 498455aabc3SBrian Somers sock_in->sin_len = sizeof *sock_in; 499455aabc3SBrian Somers 500455aabc3SBrian Somers if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { 501455aabc3SBrian Somers if (!silent) 502dd7e2610SBrian Somers log_Printf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n", 503455aabc3SBrian Somers strerror(errno)); 504455aabc3SBrian Somers close(s); 505455aabc3SBrian Somers return (-1); 506455aabc3SBrian Somers } 507455aabc3SBrian Somers 508610b185fSBrian Somers if (Enabled(bundle, OPT_SROUTES)) 509610b185fSBrian Somers route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); 510610b185fSBrian Somers 51130c2f2ffSBrian Somers bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr; 51230c2f2ffSBrian Somers bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr; 513455aabc3SBrian Somers 5141342caedSBrian Somers if (Enabled(bundle, OPT_PROXY)) 515dd7e2610SBrian Somers arp_SetProxy(bundle, bundle->ncp.ipcp.peer_ifip, s); 516455aabc3SBrian Somers 517455aabc3SBrian Somers close(s); 518455aabc3SBrian Somers return (0); 519455aabc3SBrian Somers } 520455aabc3SBrian Somers 521455aabc3SBrian Somers static struct in_addr 52230c2f2ffSBrian Somers ChooseHisAddr(struct bundle *bundle, const struct in_addr gw) 523455aabc3SBrian Somers { 524455aabc3SBrian Somers struct in_addr try; 525455aabc3SBrian Somers int f; 526455aabc3SBrian Somers 5275828db6dSBrian Somers for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { 5285828db6dSBrian Somers try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); 529dd7e2610SBrian Somers log_Printf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n", 530455aabc3SBrian Somers f, inet_ntoa(try)); 53130c2f2ffSBrian Somers if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { 532dd7e2610SBrian Somers log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); 533455aabc3SBrian Somers break; 534455aabc3SBrian Somers } 535455aabc3SBrian Somers } 536455aabc3SBrian Somers 5375828db6dSBrian Somers if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { 538dd7e2610SBrian Somers log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 539455aabc3SBrian Somers try.s_addr = INADDR_ANY; 540455aabc3SBrian Somers } 541455aabc3SBrian Somers 542455aabc3SBrian Somers return try; 543455aabc3SBrian Somers } 544455aabc3SBrian Somers 5451ae349f5Scvs2svn static void 5461ae349f5Scvs2svn IpcpInitRestartCounter(struct fsm * fp) 5471ae349f5Scvs2svn { 5487308ec68SBrian Somers /* Set fsm timer load */ 549cd9647a1SBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 550cd9647a1SBrian Somers 551cd9647a1SBrian Somers fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS; 5521ae349f5Scvs2svn fp->restart = 5; 5531ae349f5Scvs2svn } 5541ae349f5Scvs2svn 5551ae349f5Scvs2svn static void 5561ae349f5Scvs2svn IpcpSendConfigReq(struct fsm *fp) 5571ae349f5Scvs2svn { 5587308ec68SBrian Somers /* Send config REQ please */ 5598c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 560aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 5613edeb0c6SBrian Somers u_char buff[24]; 5622267893fSBrian Somers struct lcp_opt *o; 5631ae349f5Scvs2svn 5642267893fSBrian Somers o = (struct lcp_opt *)buff; 56530c2f2ffSBrian Somers 566dd7e2610SBrian Somers if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 5672267893fSBrian Somers *(u_int32_t *)o->data = ipcp->my_ip.s_addr; 5682267893fSBrian Somers INC_LCP_OPT(TY_IPADDR, 6, o); 5691ae349f5Scvs2svn } 5701ae349f5Scvs2svn 571e43ebac1SBrian Somers if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 57283d1af55SBrian Somers if (ipcp->heis1172) { 5732267893fSBrian Somers *(u_short *)o->data = htons(PROTO_VJCOMP); 5742267893fSBrian Somers INC_LCP_OPT(TY_COMPPROTO, 4, o); 5751ae349f5Scvs2svn } else { 5762267893fSBrian Somers *(u_long *)o->data = htonl(ipcp->my_compproto); 5772267893fSBrian Somers INC_LCP_OPT(TY_COMPPROTO, 6, o); 5781ae349f5Scvs2svn } 579e43ebac1SBrian Somers } 5802267893fSBrian Somers 5813edeb0c6SBrian Somers if (IsEnabled(ipcp->cfg.ns.dns_neg) && 5823edeb0c6SBrian Somers !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && 5833edeb0c6SBrian Somers !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { 5843edeb0c6SBrian Somers struct in_addr dns[2]; 5853edeb0c6SBrian Somers getdns(ipcp, dns); 5863edeb0c6SBrian Somers *(u_int32_t *)o->data = dns[0].s_addr; 5873edeb0c6SBrian Somers INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); 5883edeb0c6SBrian Somers *(u_int32_t *)o->data = dns[1].s_addr; 5893edeb0c6SBrian Somers INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); 5903edeb0c6SBrian Somers } 5913edeb0c6SBrian Somers 592dd7e2610SBrian Somers fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff); 5931ae349f5Scvs2svn } 5941ae349f5Scvs2svn 5951ae349f5Scvs2svn static void 5962267893fSBrian Somers IpcpSentTerminateReq(struct fsm * fp) 5971ae349f5Scvs2svn { 5987308ec68SBrian Somers /* Term REQ just sent by FSM */ 5991ae349f5Scvs2svn } 6001ae349f5Scvs2svn 6011ae349f5Scvs2svn static void 6022267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id) 6031ae349f5Scvs2svn { 6047308ec68SBrian Somers /* Send Term ACK please */ 605dd7e2610SBrian Somers fsm_Output(fp, CODE_TERMACK, id, NULL, 0); 6061ae349f5Scvs2svn } 6071ae349f5Scvs2svn 6081ae349f5Scvs2svn static void 6091ae349f5Scvs2svn IpcpLayerStart(struct fsm * fp) 6101ae349f5Scvs2svn { 6117308ec68SBrian Somers /* We're about to start up ! */ 612dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: IpcpLayerStart.\n", fp->link->name); 613455aabc3SBrian Somers 614565e35e5SBrian Somers /* This is where we should be setting up the interface in DEMAND mode */ 6151ae349f5Scvs2svn } 6161ae349f5Scvs2svn 6171ae349f5Scvs2svn static void 6181ae349f5Scvs2svn IpcpLayerFinish(struct fsm *fp) 6191ae349f5Scvs2svn { 6207308ec68SBrian Somers /* We're now down */ 621dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: IpcpLayerFinish.\n", fp->link->name); 6221ae349f5Scvs2svn } 6231ae349f5Scvs2svn 62468a0f0ccSBrian Somers void 625dd7e2610SBrian Somers ipcp_CleanInterface(struct ipcp *ipcp) 62668a0f0ccSBrian Somers { 62768a0f0ccSBrian Somers struct ifaliasreq ifra; 62868a0f0ccSBrian Somers struct sockaddr_in *me, *peer; 62968a0f0ccSBrian Somers int s; 63068a0f0ccSBrian Somers 63168a0f0ccSBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 63268a0f0ccSBrian Somers if (s < 0) { 633dd7e2610SBrian Somers log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno)); 63468a0f0ccSBrian Somers return; 63568a0f0ccSBrian Somers } 63668a0f0ccSBrian Somers 637610b185fSBrian Somers route_Clean(ipcp->fsm.bundle, ipcp->route); 638610b185fSBrian Somers 6391342caedSBrian Somers if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) 640dd7e2610SBrian Somers arp_ClearProxy(ipcp->fsm.bundle, ipcp->peer_ifip, s); 64168a0f0ccSBrian Somers 642503a7782SBrian Somers if (ipcp->my_ifip.s_addr != INADDR_ANY || 643503a7782SBrian Somers ipcp->peer_ifip.s_addr != INADDR_ANY) { 64468a0f0ccSBrian Somers memset(&ifra, '\0', sizeof ifra); 645faefde08SBrian Somers strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifp.Name, 646565e35e5SBrian Somers sizeof ifra.ifra_name - 1); 64768a0f0ccSBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 64868a0f0ccSBrian Somers me = (struct sockaddr_in *)&ifra.ifra_addr; 64968a0f0ccSBrian Somers peer = (struct sockaddr_in *)&ifra.ifra_broadaddr; 65068a0f0ccSBrian Somers me->sin_family = peer->sin_family = AF_INET; 65168a0f0ccSBrian Somers me->sin_len = peer->sin_len = sizeof(struct sockaddr_in); 652503a7782SBrian Somers me->sin_addr = ipcp->my_ifip; 653503a7782SBrian Somers peer->sin_addr = ipcp->peer_ifip; 6540f8037a9SBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) 655dd7e2610SBrian Somers log_Printf(LogERROR, "ipcp_CleanInterface: ioctl(SIOCDIFADDR): %s\n", 65668a0f0ccSBrian Somers strerror(errno)); 657503a7782SBrian Somers ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY; 65868a0f0ccSBrian Somers } 65968a0f0ccSBrian Somers 66068a0f0ccSBrian Somers close(s); 66168a0f0ccSBrian Somers } 66268a0f0ccSBrian Somers 6631ae349f5Scvs2svn static void 6641ae349f5Scvs2svn IpcpLayerDown(struct fsm *fp) 6651ae349f5Scvs2svn { 6667308ec68SBrian Somers /* About to come down */ 667aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 668455aabc3SBrian Somers const char *s; 669455aabc3SBrian Somers 670503a7782SBrian Somers s = inet_ntoa(ipcp->peer_ifip); 671dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: IpcpLayerDown: %s\n", fp->link->name, s); 672455aabc3SBrian Somers 67383d1af55SBrian Somers throughput_stop(&ipcp->throughput); 67483d1af55SBrian Somers throughput_log(&ipcp->throughput, LogIPCP, NULL); 675455aabc3SBrian Somers /* 676455aabc3SBrian Somers * XXX this stuff should really live in the FSM. Our config should 677455aabc3SBrian Somers * associate executable sections in files with events. 678455aabc3SBrian Somers */ 679dd7e2610SBrian Somers if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL) < 0) { 68049052c95SBrian Somers if (bundle_GetLabel(fp->bundle)) { 681dd7e2610SBrian Somers if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 68249052c95SBrian Somers LINKDOWNFILE, NULL) < 0) 683dd7e2610SBrian Somers system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL); 684455aabc3SBrian Somers } else 685dd7e2610SBrian Somers system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL); 686e43ebac1SBrian Somers } 687455aabc3SBrian Somers 688ba081e43SBrian Somers if (!(ipcp->fsm.bundle->phys_type & PHYS_DEMAND)) 689dd7e2610SBrian Somers ipcp_CleanInterface(ipcp); 6901ae349f5Scvs2svn } 6911ae349f5Scvs2svn 692dd0645c5SBrian Somers int 693dd0645c5SBrian Somers ipcp_InterfaceUp(struct ipcp *ipcp) 694dd0645c5SBrian Somers { 695dd0645c5SBrian Somers if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { 696dd0645c5SBrian Somers log_Printf(LogERROR, "IpcpLayerUp: unable to set ip address\n"); 697dd0645c5SBrian Somers return 0; 698dd0645c5SBrian Somers } 699dd0645c5SBrian Somers 700dd0645c5SBrian Somers #ifndef NOALIAS 701dd0645c5SBrian Somers if (alias_IsEnabled()) 702dd0645c5SBrian Somers (*PacketAlias.SetAddress)(ipcp->my_ip); 703dd0645c5SBrian Somers #endif 704dd0645c5SBrian Somers 705dd0645c5SBrian Somers return 1; 706dd0645c5SBrian Somers } 707dd0645c5SBrian Somers 7086f384573SBrian Somers static int 7091ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp) 7101ae349f5Scvs2svn { 7117308ec68SBrian Somers /* We're now up */ 712aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 7131ae349f5Scvs2svn char tbuff[100]; 7141ae349f5Scvs2svn 715dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: IpcpLayerUp.\n", fp->link->name); 716503a7782SBrian Somers snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip)); 717dd7e2610SBrian Somers log_Printf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip)); 7181ae349f5Scvs2svn 719503a7782SBrian Somers if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 720eaa4df37SBrian Somers sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); 7211ae349f5Scvs2svn 722dd0645c5SBrian Somers if (!ipcp_InterfaceUp(ipcp)) 7236f384573SBrian Somers return 0; 724455aabc3SBrian Somers 725455aabc3SBrian Somers /* 726455aabc3SBrian Somers * XXX this stuff should really live in the FSM. Our config should 727455aabc3SBrian Somers * associate executable sections in files with events. 728455aabc3SBrian Somers */ 729dd7e2610SBrian Somers if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, NULL) 730e43ebac1SBrian Somers < 0) { 73149052c95SBrian Somers if (bundle_GetLabel(fp->bundle)) { 732dd7e2610SBrian Somers if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 73349052c95SBrian Somers LINKUPFILE, NULL) < 0) 734dd7e2610SBrian Somers system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL); 735455aabc3SBrian Somers } else 736dd7e2610SBrian Somers system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL); 737e43ebac1SBrian Somers } 738455aabc3SBrian Somers 7391342caedSBrian Somers throughput_start(&ipcp->throughput, "IPCP throughput", 7401342caedSBrian Somers Enabled(fp->bundle, OPT_THROUGHPUT)); 741b6217683SBrian Somers bundle_DisplayPrompt(fp->bundle); 7426f384573SBrian Somers return 1; 7431ae349f5Scvs2svn } 7441ae349f5Scvs2svn 7451ae349f5Scvs2svn static int 7461ae349f5Scvs2svn AcceptableAddr(struct in_range *prange, struct in_addr ipaddr) 7471ae349f5Scvs2svn { 7487308ec68SBrian Somers /* Is the given IP in the given range ? */ 7491ae349f5Scvs2svn return (prange->ipaddr.s_addr & prange->mask.s_addr) == 7501ae349f5Scvs2svn (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 7511ae349f5Scvs2svn } 7521ae349f5Scvs2svn 7531ae349f5Scvs2svn static void 75430c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type, 75530c2f2ffSBrian Somers struct fsm_decode *dec) 7561ae349f5Scvs2svn { 7577308ec68SBrian Somers /* Deal with incoming PROTO_IPCP */ 758aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 7591ae349f5Scvs2svn int type, length; 760fe3125a0SBrian Somers u_int32_t compproto; 7611ae349f5Scvs2svn struct compreq *pcomp; 7623edeb0c6SBrian Somers struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; 76330c2f2ffSBrian Somers char tbuff[100], tbuff2[100]; 7643edeb0c6SBrian Somers int gotdns, gotdnsnak; 7653edeb0c6SBrian Somers 7663edeb0c6SBrian Somers gotdns = 0; 7673edeb0c6SBrian Somers gotdnsnak = 0; 7683edeb0c6SBrian Somers dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; 7691ae349f5Scvs2svn 7701ae349f5Scvs2svn while (plen >= sizeof(struct fsmconfig)) { 7711ae349f5Scvs2svn type = *cp; 7721ae349f5Scvs2svn length = cp[1]; 773d47dceb8SBrian Somers 774d47dceb8SBrian Somers if (length == 0) { 775dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); 776d47dceb8SBrian Somers break; 777d47dceb8SBrian Somers } 778d47dceb8SBrian Somers 7791ae349f5Scvs2svn if (type < NCFTYPES) 7801ae349f5Scvs2svn snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); 7811ae349f5Scvs2svn else if (type > 128 && type < 128 + NCFTYPES128) 7821ae349f5Scvs2svn snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); 7831ae349f5Scvs2svn else 7841ae349f5Scvs2svn snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); 7851ae349f5Scvs2svn 7861ae349f5Scvs2svn switch (type) { 7871ae349f5Scvs2svn case TY_IPADDR: /* RFC1332 */ 788fe3125a0SBrian Somers ipaddr.s_addr = *(u_int32_t *)(cp + 2); 789dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 7901ae349f5Scvs2svn 7911ae349f5Scvs2svn switch (mode_type) { 7921ae349f5Scvs2svn case MODE_REQ: 793503a7782SBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 7941ae349f5Scvs2svn if (ipaddr.s_addr == INADDR_ANY || 795503a7782SBrian Somers iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || 79630c2f2ffSBrian Somers ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, 79730c2f2ffSBrian Somers ipaddr, 1)) { 798dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: Address invalid or already in use\n", 7991ae349f5Scvs2svn inet_ntoa(ipaddr)); 8008390b576SBrian Somers if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0) 8018390b576SBrian Somers /* 8028390b576SBrian Somers * If we've already got a valid address configured for the peer 803565e35e5SBrian Somers * (in DEMAND mode), try NAKing with that so that we don't 8048390b576SBrian Somers * have to upset things too much. 8058390b576SBrian Somers */ 8068390b576SBrian Somers ipcp->peer_ip = ipcp->peer_ifip; 8078390b576SBrian Somers else 8088390b576SBrian Somers /* Just pick an IP number from our list */ 809503a7782SBrian Somers ipcp->peer_ip = ChooseHisAddr 81030c2f2ffSBrian Somers (fp->bundle, ipcp->cfg.my_range.ipaddr); 8118390b576SBrian Somers 812503a7782SBrian Somers if (ipcp->peer_ip.s_addr == INADDR_ANY) { 81330c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 81430c2f2ffSBrian Somers dec->rejend += length; 8151ae349f5Scvs2svn } else { 81630c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 81730c2f2ffSBrian Somers memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); 81830c2f2ffSBrian Somers dec->nakend += length; 8191ae349f5Scvs2svn } 8201ae349f5Scvs2svn break; 8211ae349f5Scvs2svn } 822503a7782SBrian Somers } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { 8231ae349f5Scvs2svn /* 8248390b576SBrian Somers * If destination address is not acceptable, NAK with what we 8251ae349f5Scvs2svn * want to use. 8261ae349f5Scvs2svn */ 82730c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 8288390b576SBrian Somers if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) == 8298390b576SBrian Somers (ipcp->cfg.peer_range.ipaddr.s_addr & 8308390b576SBrian Somers ipcp->cfg.peer_range.mask.s_addr)) 8318390b576SBrian Somers /* We prefer the already-configured address */ 8328390b576SBrian Somers memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2); 8338390b576SBrian Somers else 83430c2f2ffSBrian Somers memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); 83530c2f2ffSBrian Somers dec->nakend += length; 8361ae349f5Scvs2svn break; 8371ae349f5Scvs2svn } 838503a7782SBrian Somers ipcp->peer_ip = ipaddr; 83930c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 84030c2f2ffSBrian Somers dec->ackend += length; 8411ae349f5Scvs2svn break; 8421ae349f5Scvs2svn case MODE_NAK: 843503a7782SBrian Somers if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { 8441ae349f5Scvs2svn /* Use address suggested by peer */ 8451ae349f5Scvs2svn snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 846503a7782SBrian Somers inet_ntoa(ipcp->my_ip)); 847dd7e2610SBrian Somers log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 848503a7782SBrian Somers ipcp->my_ip = ipaddr; 8491ae349f5Scvs2svn } else { 850dd7e2610SBrian Somers log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, 8518390b576SBrian Somers "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 852dd7e2610SBrian Somers fsm_Close(&ipcp->fsm); 8531ae349f5Scvs2svn } 8541ae349f5Scvs2svn break; 8551ae349f5Scvs2svn case MODE_REJ: 856503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 8571ae349f5Scvs2svn break; 8581ae349f5Scvs2svn } 8591ae349f5Scvs2svn break; 8601ae349f5Scvs2svn case TY_COMPPROTO: 861fe3125a0SBrian Somers compproto = htonl(*(u_int32_t *)(cp + 2)); 862dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 8631ae349f5Scvs2svn 8641ae349f5Scvs2svn switch (mode_type) { 8651ae349f5Scvs2svn case MODE_REQ: 8661342caedSBrian Somers if (!IsAccepted(ipcp->cfg.vj.neg)) { 86730c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 86830c2f2ffSBrian Somers dec->rejend += length; 8691ae349f5Scvs2svn } else { 8701ae349f5Scvs2svn pcomp = (struct compreq *) (cp + 2); 8711ae349f5Scvs2svn switch (length) { 8721ae349f5Scvs2svn case 4: /* RFC1172 */ 8731ae349f5Scvs2svn if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 874dd7e2610SBrian Somers log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); 87583d1af55SBrian Somers ipcp->heis1172 = 1; 876503a7782SBrian Somers ipcp->peer_compproto = compproto; 87730c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 87830c2f2ffSBrian Somers dec->ackend += length; 8791ae349f5Scvs2svn } else { 88030c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 8811ae349f5Scvs2svn pcomp->proto = htons(PROTO_VJCOMP); 88230c2f2ffSBrian Somers memcpy(dec->nakend+2, &pcomp, 2); 88330c2f2ffSBrian Somers dec->nakend += length; 8841ae349f5Scvs2svn } 8851ae349f5Scvs2svn break; 8861ae349f5Scvs2svn case 6: /* RFC1332 */ 8871ae349f5Scvs2svn if (ntohs(pcomp->proto) == PROTO_VJCOMP 888503a7782SBrian Somers && pcomp->slots <= MAX_VJ_STATES 889503a7782SBrian Somers && pcomp->slots >= MIN_VJ_STATES) { 890503a7782SBrian Somers ipcp->peer_compproto = compproto; 89183d1af55SBrian Somers ipcp->heis1172 = 0; 89230c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 89330c2f2ffSBrian Somers dec->ackend += length; 8941ae349f5Scvs2svn } else { 89530c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 8961ae349f5Scvs2svn pcomp->proto = htons(PROTO_VJCOMP); 897503a7782SBrian Somers pcomp->slots = DEF_VJ_STATES; 8981ae349f5Scvs2svn pcomp->compcid = 0; 89930c2f2ffSBrian Somers memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 90030c2f2ffSBrian Somers dec->nakend += length; 9011ae349f5Scvs2svn } 9021ae349f5Scvs2svn break; 9031ae349f5Scvs2svn default: 90430c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 90530c2f2ffSBrian Somers dec->rejend += length; 9061ae349f5Scvs2svn break; 9071ae349f5Scvs2svn } 9081ae349f5Scvs2svn } 9091ae349f5Scvs2svn break; 9101ae349f5Scvs2svn case MODE_NAK: 911dd7e2610SBrian Somers log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 912503a7782SBrian Somers tbuff, ipcp->my_compproto, compproto); 913503a7782SBrian Somers ipcp->my_compproto = compproto; 9141ae349f5Scvs2svn break; 9151ae349f5Scvs2svn case MODE_REJ: 916503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 9171ae349f5Scvs2svn break; 9181ae349f5Scvs2svn } 9191ae349f5Scvs2svn break; 9201ae349f5Scvs2svn case TY_IPADDRS: /* RFC1172 */ 921fe3125a0SBrian Somers ipaddr.s_addr = *(u_int32_t *)(cp + 2); 922fe3125a0SBrian Somers dstipaddr.s_addr = *(u_int32_t *)(cp + 6); 9231ae349f5Scvs2svn snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 924dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 9251ae349f5Scvs2svn 9261ae349f5Scvs2svn switch (mode_type) { 9271ae349f5Scvs2svn case MODE_REQ: 928503a7782SBrian Somers ipcp->peer_ip = ipaddr; 929503a7782SBrian Somers ipcp->my_ip = dstipaddr; 93030c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 93130c2f2ffSBrian Somers dec->ackend += length; 9321ae349f5Scvs2svn break; 9331ae349f5Scvs2svn case MODE_NAK: 9341ae349f5Scvs2svn snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff, 935503a7782SBrian Somers inet_ntoa(ipcp->my_ip)); 936dd7e2610SBrian Somers log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 937503a7782SBrian Somers ipcp->my_ip = ipaddr; 938503a7782SBrian Somers ipcp->peer_ip = dstipaddr; 9391ae349f5Scvs2svn break; 9401ae349f5Scvs2svn case MODE_REJ: 941503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 9421ae349f5Scvs2svn break; 9431ae349f5Scvs2svn } 9441ae349f5Scvs2svn break; 9451ae349f5Scvs2svn 9463edeb0c6SBrian Somers case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ 9471ae349f5Scvs2svn case TY_SECONDARY_DNS: 9483edeb0c6SBrian Somers ipaddr.s_addr = *(u_int32_t *)(cp + 2); 949dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 9503edeb0c6SBrian Somers 95130c2f2ffSBrian Somers switch (mode_type) { 95230c2f2ffSBrian Somers case MODE_REQ: 9533edeb0c6SBrian Somers if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { 9543edeb0c6SBrian Somers ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 95530c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 95630c2f2ffSBrian Somers dec->rejend += length; 9571ae349f5Scvs2svn break; 9581ae349f5Scvs2svn } 9593edeb0c6SBrian Somers if (!gotdns) { 9603edeb0c6SBrian Somers dns[0] = ipcp->cfg.ns.dns[0]; 9613edeb0c6SBrian Somers dns[1] = ipcp->cfg.ns.dns[1]; 9623edeb0c6SBrian Somers if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) 9633edeb0c6SBrian Somers getdns(ipcp, dns); 9643edeb0c6SBrian Somers gotdns = 1; 9653edeb0c6SBrian Somers } 9663edeb0c6SBrian Somers have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; 9671ae349f5Scvs2svn 9683edeb0c6SBrian Somers if (ipaddr.s_addr != have_ip.s_addr) { 9691ae349f5Scvs2svn /* 9703edeb0c6SBrian Somers * The client has got the DNS stuff wrong (first request) so 9711ae349f5Scvs2svn * we'll tell 'em how it is 9721ae349f5Scvs2svn */ 97330c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ 9743edeb0c6SBrian Somers memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); 97530c2f2ffSBrian Somers dec->nakend += length; 9763edeb0c6SBrian Somers } else { 9771ae349f5Scvs2svn /* 9781ae349f5Scvs2svn * Otherwise they have it right (this time) so we send a ack packet 9791ae349f5Scvs2svn * back confirming it... end of story 9801ae349f5Scvs2svn */ 98130c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 98230c2f2ffSBrian Somers dec->ackend += length; 9833edeb0c6SBrian Somers } 9841ae349f5Scvs2svn break; 9851ae349f5Scvs2svn case MODE_NAK: /* what does this mean?? */ 9863edeb0c6SBrian Somers if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 9873edeb0c6SBrian Somers gotdnsnak = 1; 9883edeb0c6SBrian Somers dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr = 9893edeb0c6SBrian Somers *(u_int32_t *)(cp + 2); 9903edeb0c6SBrian Somers } 9911ae349f5Scvs2svn break; 9923edeb0c6SBrian Somers case MODE_REJ: /* Can't do much, stop asking */ 9933edeb0c6SBrian Somers ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); 9941ae349f5Scvs2svn break; 9951ae349f5Scvs2svn } 9961ae349f5Scvs2svn break; 9971ae349f5Scvs2svn 9983edeb0c6SBrian Somers case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ 9991ae349f5Scvs2svn case TY_SECONDARY_NBNS: 10003edeb0c6SBrian Somers ipaddr.s_addr = *(u_int32_t *)(cp + 2); 1001dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 10023edeb0c6SBrian Somers 100330c2f2ffSBrian Somers switch (mode_type) { 100430c2f2ffSBrian Somers case MODE_REQ: 10053edeb0c6SBrian Somers have_ip.s_addr = 10063edeb0c6SBrian Somers ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; 10073edeb0c6SBrian Somers 10083edeb0c6SBrian Somers if (have_ip.s_addr == INADDR_ANY) { 1009dd7e2610SBrian Somers log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); 10103edeb0c6SBrian Somers ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 101130c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 101230c2f2ffSBrian Somers dec->rejend += length; 10131ae349f5Scvs2svn break; 10141ae349f5Scvs2svn } 10153edeb0c6SBrian Somers 10163edeb0c6SBrian Somers if (ipaddr.s_addr != have_ip.s_addr) { 101730c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 10183edeb0c6SBrian Somers memcpy(dec->nakend+2, &have_ip.s_addr, length); 101930c2f2ffSBrian Somers dec->nakend += length; 10203edeb0c6SBrian Somers } else { 102130c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 102230c2f2ffSBrian Somers dec->ackend += length; 10233edeb0c6SBrian Somers } 10241ae349f5Scvs2svn break; 10251ae349f5Scvs2svn case MODE_NAK: 1026dd7e2610SBrian Somers log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 10271ae349f5Scvs2svn break; 10281ae349f5Scvs2svn case MODE_REJ: 1029dd7e2610SBrian Somers log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 10301ae349f5Scvs2svn break; 10311ae349f5Scvs2svn } 10321ae349f5Scvs2svn break; 10331ae349f5Scvs2svn 10341ae349f5Scvs2svn default: 103530c2f2ffSBrian Somers if (mode_type != MODE_NOP) { 103683d1af55SBrian Somers ipcp->my_reject |= (1 << type); 103730c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 103830c2f2ffSBrian Somers dec->rejend += length; 103930c2f2ffSBrian Somers } 10401ae349f5Scvs2svn break; 10411ae349f5Scvs2svn } 10421ae349f5Scvs2svn plen -= length; 10431ae349f5Scvs2svn cp += length; 10441ae349f5Scvs2svn } 10451342caedSBrian Somers 10463edeb0c6SBrian Somers if (gotdnsnak) 10473edeb0c6SBrian Somers if (!setdns(ipcp, dnsnak)) { 10483edeb0c6SBrian Somers ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); 10493edeb0c6SBrian Somers ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); 10503edeb0c6SBrian Somers } 10513edeb0c6SBrian Somers 1052e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 10531342caedSBrian Somers if (dec->rejend != dec->rej) { 10541342caedSBrian Somers /* rejects are preferred */ 10551342caedSBrian Somers dec->ackend = dec->ack; 10561342caedSBrian Somers dec->nakend = dec->nak; 10571342caedSBrian Somers } else if (dec->nakend != dec->nak) 10581342caedSBrian Somers /* then NAKs */ 10591342caedSBrian Somers dec->ackend = dec->ack; 10601ae349f5Scvs2svn } 1061e43ebac1SBrian Somers } 10621ae349f5Scvs2svn 10631ae349f5Scvs2svn void 1064641684cdSBrian Somers ipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp) 10651ae349f5Scvs2svn { 10667308ec68SBrian Somers /* Got PROTO_IPCP from link */ 1067641684cdSBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 1068dd7e2610SBrian Somers fsm_Input(&ipcp->fsm, bp); 1069641684cdSBrian Somers else { 1070641684cdSBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK) 1071641684cdSBrian Somers log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", 1072641684cdSBrian Somers ipcp->fsm.link->name, bundle_PhaseName(bundle)); 1073641684cdSBrian Somers mbuf_Free(bp); 1074641684cdSBrian Somers } 10751ae349f5Scvs2svn } 10761ae349f5Scvs2svn 10771ae349f5Scvs2svn int 1078dd7e2610SBrian Somers ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 10791ae349f5Scvs2svn { 10805828db6dSBrian Somers struct ipcp *ipcp = &bundle->ncp.ipcp; 10815828db6dSBrian Somers 10827308ec68SBrian Somers /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 10835828db6dSBrian Somers memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 10845828db6dSBrian Somers iplist_reset(&ipcp->cfg.peer_list); 10851ae349f5Scvs2svn if (strpbrk(hisaddr, ",-")) { 10865828db6dSBrian Somers iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); 10875828db6dSBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 10885828db6dSBrian Somers iplist_setrandpos(&ipcp->cfg.peer_list); 108930c2f2ffSBrian Somers ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); 10905828db6dSBrian Somers if (ipcp->peer_ip.s_addr == INADDR_ANY) { 1091dd7e2610SBrian Somers log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); 10921ae349f5Scvs2svn return(0); 10931ae349f5Scvs2svn } 10945828db6dSBrian Somers ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; 10955828db6dSBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 10965828db6dSBrian Somers ipcp->cfg.peer_range.width = 32; 10971ae349f5Scvs2svn } else { 1098dd7e2610SBrian Somers log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); 10991ae349f5Scvs2svn return 0; 11001ae349f5Scvs2svn } 11015828db6dSBrian Somers } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr, 11025828db6dSBrian Somers &ipcp->cfg.peer_range.mask, 11035828db6dSBrian Somers &ipcp->cfg.peer_range.width) != 0) { 11045828db6dSBrian Somers ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; 11051ae349f5Scvs2svn 110630c2f2ffSBrian Somers if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, 110730c2f2ffSBrian Somers ipcp->cfg.peer_range.ipaddr, 0) < 0) { 11085828db6dSBrian Somers ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY; 11095828db6dSBrian Somers ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY; 11101ae349f5Scvs2svn return 0; 11111ae349f5Scvs2svn } 11121ae349f5Scvs2svn } else 11131ae349f5Scvs2svn return 0; 11141ae349f5Scvs2svn 11151ae349f5Scvs2svn return 1; 11161ae349f5Scvs2svn } 1117