1af57ed9fSAtsushi Murai /* 2af57ed9fSAtsushi Murai * PPP IP Control Protocol (IPCP) Module 3af57ed9fSAtsushi Murai * 4af57ed9fSAtsushi Murai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5af57ed9fSAtsushi Murai * 6af57ed9fSAtsushi Murai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7af57ed9fSAtsushi Murai * 8af57ed9fSAtsushi Murai * Redistribution and use in source and binary forms are permitted 9af57ed9fSAtsushi Murai * provided that the above copyright notice and this paragraph are 10af57ed9fSAtsushi Murai * duplicated in all such forms and that any documentation, 11af57ed9fSAtsushi Murai * advertising materials, and other materials related to such 12af57ed9fSAtsushi Murai * distribution and use acknowledge that the software was developed 13af57ed9fSAtsushi Murai * by the Internet Initiative Japan, Inc. The name of the 14af57ed9fSAtsushi Murai * IIJ may not be used to endorse or promote products derived 15af57ed9fSAtsushi Murai * from this software without specific prior written permission. 16af57ed9fSAtsushi Murai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17af57ed9fSAtsushi Murai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18af57ed9fSAtsushi Murai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19af57ed9fSAtsushi Murai * 2097d92980SPeter Wemm * $FreeBSD$ 21af57ed9fSAtsushi Murai * 22af57ed9fSAtsushi Murai * TODO: 235d9e6103SBrian Somers * o Support IPADDRS properly 245d9e6103SBrian Somers * o Validate the length in IpcpDecodeConfig 25af57ed9fSAtsushi Murai */ 2675240ed1SBrian Somers #include <sys/param.h> 275b4c5b00SBrian Somers #include <netinet/in_systm.h> 285b4c5b00SBrian Somers #include <netinet/in.h> 295b4c5b00SBrian Somers #include <netinet/ip.h> 305b4c5b00SBrian Somers #include <arpa/inet.h> 315b4c5b00SBrian Somers #include <sys/socket.h> 323afe5ccbSBrian Somers #include <net/route.h> 3375240ed1SBrian Somers #include <netdb.h> 341fa665f5SBrian Somers #include <sys/un.h> 3575240ed1SBrian Somers 36119386a3SBrian Somers #include <errno.h> 373edeb0c6SBrian Somers #include <fcntl.h> 383edeb0c6SBrian Somers #include <resolv.h> 39d1a3ea47SBrian Somers #include <stdlib.h> 4075240ed1SBrian Somers #include <string.h> 416140ba11SBrian Somers #include <termios.h> 4275240ed1SBrian Somers #include <unistd.h> 4375240ed1SBrian Somers 4467b072f7SBrian Somers #ifndef NONAT 457884358fSBrian Somers #ifdef __FreeBSD__ 461595bacdSBrian Somers #include <alias.h> 477884358fSBrian Somers #else 487884358fSBrian Somers #include "alias.h" 491595bacdSBrian Somers #endif 501595bacdSBrian Somers #endif 515d9e6103SBrian Somers #include "layer.h" 529e8ec64bSBrian Somers #include "ua.h" 53c9e11a11SBrian Somers #include "defs.h" 54b6e82f33SBrian Somers #include "command.h" 5575240ed1SBrian Somers #include "mbuf.h" 5675240ed1SBrian Somers #include "log.h" 5775240ed1SBrian Somers #include "timer.h" 58af57ed9fSAtsushi Murai #include "fsm.h" 595d9e6103SBrian Somers #include "proto.h" 60af57ed9fSAtsushi Murai #include "lcp.h" 61bcc332bdSBrian Somers #include "iplist.h" 629a0b991fSBrian Somers #include "throughput.h" 631ae349f5Scvs2svn #include "slcompress.h" 645a72b6edSBrian Somers #include "lqr.h" 655a72b6edSBrian Somers #include "hdlc.h" 66eaa4df37SBrian Somers #include "ipcp.h" 679c97abd8SBrian Somers #include "filter.h" 682f786681SBrian Somers #include "descriptor.h" 691ae349f5Scvs2svn #include "vjcomp.h" 706140ba11SBrian Somers #include "async.h" 713b0f8d2eSBrian Somers #include "ccp.h" 728c07a7b2SBrian Somers #include "link.h" 7363b73463SBrian Somers #include "physical.h" 743b0f8d2eSBrian Somers #include "mp.h" 75972a1bcfSBrian Somers #ifndef NORADIUS 76972a1bcfSBrian Somers #include "radius.h" 77972a1bcfSBrian Somers #endif 783b0f8d2eSBrian Somers #include "bundle.h" 79455aabc3SBrian Somers #include "id.h" 80455aabc3SBrian Somers #include "arp.h" 81455aabc3SBrian Somers #include "systems.h" 8285b542cfSBrian Somers #include "prompt.h" 83610b185fSBrian Somers #include "route.h" 848fa6ebe4SBrian Somers #include "iface.h" 85442f8495SBrian Somers #include "ip.h" 86af57ed9fSAtsushi Murai 87503a7782SBrian Somers #undef REJECTED 88503a7782SBrian Somers #define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) 893edeb0c6SBrian Somers #define issep(ch) ((ch) == ' ' || (ch) == '\t') 903edeb0c6SBrian Somers #define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.') 91d8e55738SJordan K. Hubbard 92442f8495SBrian Somers static u_short default_urgent_ports[] = { 93442f8495SBrian Somers 21, /* ftp */ 94442f8495SBrian Somers 22, /* ssh */ 95442f8495SBrian Somers 23, /* telnet */ 96442f8495SBrian Somers 513, /* login */ 97442f8495SBrian Somers 514, /* shell */ 98442f8495SBrian Somers 543, /* klogin */ 99442f8495SBrian Somers 544 /* kshell */ 100442f8495SBrian Somers }; 101442f8495SBrian Somers 102442f8495SBrian Somers #define NDEFPORTS (sizeof default_urgent_ports / sizeof default_urgent_ports[0]) 103442f8495SBrian Somers 104442f8495SBrian Somers int 105442f8495SBrian Somers ipcp_IsUrgentPort(struct ipcp *ipcp, u_short src, u_short dst) 106442f8495SBrian Somers { 107442f8495SBrian Somers int f; 108442f8495SBrian Somers 109442f8495SBrian Somers for (f = 0; f < ipcp->cfg.urgent.nports; f++) 110442f8495SBrian Somers if (ipcp->cfg.urgent.port[f] == src || ipcp->cfg.urgent.port[f] == dst) 111442f8495SBrian Somers return 1; 112442f8495SBrian Somers 113442f8495SBrian Somers return 0; 114442f8495SBrian Somers } 115442f8495SBrian Somers 116442f8495SBrian Somers void 117442f8495SBrian Somers ipcp_AddUrgentPort(struct ipcp *ipcp, u_short port) 118442f8495SBrian Somers { 119442f8495SBrian Somers u_short *newport; 120442f8495SBrian Somers int p; 121442f8495SBrian Somers 122442f8495SBrian Somers if (ipcp->cfg.urgent.nports == ipcp->cfg.urgent.maxports) { 123442f8495SBrian Somers ipcp->cfg.urgent.maxports += 10; 124442f8495SBrian Somers newport = (u_short *)realloc(ipcp->cfg.urgent.port, 125442f8495SBrian Somers ipcp->cfg.urgent.maxports * sizeof(u_short)); 126442f8495SBrian Somers if (newport == NULL) { 127442f8495SBrian Somers log_Printf(LogERROR, "ipcp_AddUrgentPort: realloc: %s\n", 128442f8495SBrian Somers strerror(errno)); 129442f8495SBrian Somers ipcp->cfg.urgent.maxports -= 10; 130442f8495SBrian Somers return; 131442f8495SBrian Somers } 132442f8495SBrian Somers ipcp->cfg.urgent.port = newport; 133442f8495SBrian Somers } 134442f8495SBrian Somers 135442f8495SBrian Somers for (p = 0; p < ipcp->cfg.urgent.nports; p++) 136442f8495SBrian Somers if (ipcp->cfg.urgent.port[p] == port) { 137442f8495SBrian Somers log_Printf(LogWARN, "%u: Port already set to urgent\n", port); 138442f8495SBrian Somers break; 139442f8495SBrian Somers } else if (ipcp->cfg.urgent.port[p] > port) { 140442f8495SBrian Somers memmove(ipcp->cfg.urgent.port + p + 1, ipcp->cfg.urgent.port + p, 141442f8495SBrian Somers (ipcp->cfg.urgent.nports - p) * sizeof(u_short)); 142442f8495SBrian Somers ipcp->cfg.urgent.port[p] = port; 143442f8495SBrian Somers ipcp->cfg.urgent.nports++; 144442f8495SBrian Somers break; 145442f8495SBrian Somers } 146442f8495SBrian Somers 147442f8495SBrian Somers if (p == ipcp->cfg.urgent.nports) 148442f8495SBrian Somers ipcp->cfg.urgent.port[ipcp->cfg.urgent.nports++] = port; 149442f8495SBrian Somers } 150442f8495SBrian Somers 151442f8495SBrian Somers void 152442f8495SBrian Somers ipcp_RemoveUrgentPort(struct ipcp *ipcp, u_short port) 153442f8495SBrian Somers { 154442f8495SBrian Somers int p; 155442f8495SBrian Somers 156442f8495SBrian Somers for (p = 0; p < ipcp->cfg.urgent.nports; p++) 157442f8495SBrian Somers if (ipcp->cfg.urgent.port[p] == port) { 158442f8495SBrian Somers if (p != ipcp->cfg.urgent.nports - 1) 159442f8495SBrian Somers memmove(ipcp->cfg.urgent.port + p, ipcp->cfg.urgent.port + p + 1, 160442f8495SBrian Somers (ipcp->cfg.urgent.nports - p - 1) * sizeof(u_short)); 161442f8495SBrian Somers ipcp->cfg.urgent.nports--; 162442f8495SBrian Somers return; 163442f8495SBrian Somers } 164442f8495SBrian Somers 165442f8495SBrian Somers if (p == ipcp->cfg.urgent.nports) 166442f8495SBrian Somers log_Printf(LogWARN, "%u: Port not set to urgent\n", port); 167442f8495SBrian Somers } 168442f8495SBrian Somers 169442f8495SBrian Somers void 170442f8495SBrian Somers ipcp_ClearUrgentPorts(struct ipcp *ipcp) 171442f8495SBrian Somers { 172442f8495SBrian Somers ipcp->cfg.urgent.nports = 0; 173442f8495SBrian Somers } 174442f8495SBrian Somers 17529e275ceSBrian Somers struct compreq { 17629e275ceSBrian Somers u_short proto; 17729e275ceSBrian Somers u_char slots; 17829e275ceSBrian Somers u_char compcid; 17929e275ceSBrian Somers }; 18075240ed1SBrian Somers 1816f384573SBrian Somers static int IpcpLayerUp(struct fsm *); 1821ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *); 183927145beSBrian Somers static void IpcpLayerStart(struct fsm *); 184927145beSBrian Somers static void IpcpLayerFinish(struct fsm *); 185479508cfSBrian Somers static void IpcpInitRestartCounter(struct fsm *, int); 1867308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *); 1872267893fSBrian Somers static void IpcpSentTerminateReq(struct fsm *); 1882267893fSBrian Somers static void IpcpSendTerminateAck(struct fsm *, u_char); 18930c2f2ffSBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int, 19030c2f2ffSBrian Somers struct fsm_decode *); 191af57ed9fSAtsushi Murai 19283d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = { 193af57ed9fSAtsushi Murai IpcpLayerUp, 194af57ed9fSAtsushi Murai IpcpLayerDown, 195af57ed9fSAtsushi Murai IpcpLayerStart, 196af57ed9fSAtsushi Murai IpcpLayerFinish, 197af57ed9fSAtsushi Murai IpcpInitRestartCounter, 198af57ed9fSAtsushi Murai IpcpSendConfigReq, 1992267893fSBrian Somers IpcpSentTerminateReq, 200af57ed9fSAtsushi Murai IpcpSendTerminateAck, 201af57ed9fSAtsushi Murai IpcpDecodeConfig, 202dd7e2610SBrian Somers fsm_NullRecvResetReq, 203dd7e2610SBrian Somers fsm_NullRecvResetAck 204af57ed9fSAtsushi Murai }; 205af57ed9fSAtsushi Murai 206b6e82f33SBrian Somers static const char *cftypes[] = { 2079e836af5SBrian Somers /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 2089e836af5SBrian Somers "???", 2099e836af5SBrian Somers "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ 2109e836af5SBrian Somers "COMPPROTO", /* 2: IP-Compression-Protocol */ 2119e836af5SBrian Somers "IPADDR", /* 3: IP-Address */ 212af57ed9fSAtsushi Murai }; 213af57ed9fSAtsushi Murai 21470ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 2159e836af5SBrian Somers 216b6e82f33SBrian Somers static const char *cftypes128[] = { 2179e836af5SBrian Somers /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 2189e836af5SBrian Somers "???", 2199e836af5SBrian Somers "PRIDNS", /* 129: Primary DNS Server Address */ 2209e836af5SBrian Somers "PRINBNS", /* 130: Primary NBNS Server Address */ 2219e836af5SBrian Somers "SECDNS", /* 131: Secondary DNS Server Address */ 2229e836af5SBrian Somers "SECNBNS", /* 132: Secondary NBNS Server Address */ 2239e836af5SBrian Somers }; 2249e836af5SBrian Somers 22570ee81ffSBrian Somers #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) 2269e836af5SBrian Somers 2279a0b991fSBrian Somers void 2285828db6dSBrian Somers ipcp_AddInOctets(struct ipcp *ipcp, int n) 229af57ed9fSAtsushi Murai { 2305828db6dSBrian Somers throughput_addin(&ipcp->throughput, n); 231af57ed9fSAtsushi Murai } 232af57ed9fSAtsushi Murai 2339a0b991fSBrian Somers void 2345828db6dSBrian Somers ipcp_AddOutOctets(struct ipcp *ipcp, int n) 235af57ed9fSAtsushi Murai { 2365828db6dSBrian Somers throughput_addout(&ipcp->throughput, n); 2371ae349f5Scvs2svn } 2381ae349f5Scvs2svn 2393edeb0c6SBrian Somers static void 2403edeb0c6SBrian Somers getdns(struct ipcp *ipcp, struct in_addr addr[2]) 2413edeb0c6SBrian Somers { 2423edeb0c6SBrian Somers FILE *fp; 2433edeb0c6SBrian Somers 2443edeb0c6SBrian Somers addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 2453edeb0c6SBrian Somers if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 2463edeb0c6SBrian Somers char buf[LINE_LEN], *cp, *end; 2473edeb0c6SBrian Somers int n; 2483edeb0c6SBrian Somers 2493edeb0c6SBrian Somers n = 0; 2503edeb0c6SBrian Somers buf[sizeof buf - 1] = '\0'; 2513edeb0c6SBrian Somers while (fgets(buf, sizeof buf - 1, fp)) { 2523edeb0c6SBrian Somers if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) { 2533edeb0c6SBrian Somers for (cp = buf + 11; issep(*cp); cp++) 2543edeb0c6SBrian Somers ; 2553edeb0c6SBrian Somers for (end = cp; isip(*end); end++) 2563edeb0c6SBrian Somers ; 2573edeb0c6SBrian Somers *end = '\0'; 2583edeb0c6SBrian Somers if (inet_aton(cp, addr+n) && ++n == 2) 2593edeb0c6SBrian Somers break; 2603edeb0c6SBrian Somers } 2613edeb0c6SBrian Somers } 2623edeb0c6SBrian Somers if (n == 1) 2633edeb0c6SBrian Somers addr[1] = addr[0]; 2643edeb0c6SBrian Somers fclose(fp); 2653edeb0c6SBrian Somers } 2663edeb0c6SBrian Somers } 2673edeb0c6SBrian Somers 2683edeb0c6SBrian Somers static int 2693edeb0c6SBrian Somers setdns(struct ipcp *ipcp, struct in_addr addr[2]) 2703edeb0c6SBrian Somers { 2713edeb0c6SBrian Somers FILE *fp; 2723edeb0c6SBrian Somers char wbuf[LINE_LEN + 54]; 2733edeb0c6SBrian Somers int wlen; 2743edeb0c6SBrian Somers 2753edeb0c6SBrian Somers if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) { 2763edeb0c6SBrian Somers struct in_addr old[2]; 2773edeb0c6SBrian Somers 2783edeb0c6SBrian Somers getdns(ipcp, old); 2793edeb0c6SBrian Somers if (addr[0].s_addr == INADDR_ANY) 2803edeb0c6SBrian Somers addr[0] = old[0]; 2813edeb0c6SBrian Somers if (addr[1].s_addr == INADDR_ANY) 2823edeb0c6SBrian Somers addr[1] = old[1]; 2833edeb0c6SBrian Somers } 2843edeb0c6SBrian Somers 2853edeb0c6SBrian Somers if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) { 286dd7e2610SBrian Somers log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n", 2873edeb0c6SBrian Somers _PATH_RESCONF); 2883edeb0c6SBrian Somers return 0; 2893edeb0c6SBrian Somers } 2903edeb0c6SBrian Somers 2913edeb0c6SBrian Somers wlen = 0; 2923edeb0c6SBrian Somers if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 2933edeb0c6SBrian Somers char buf[LINE_LEN]; 2943edeb0c6SBrian Somers int len; 2953edeb0c6SBrian Somers 2963edeb0c6SBrian Somers buf[sizeof buf - 1] = '\0'; 2973edeb0c6SBrian Somers while (fgets(buf, sizeof buf - 1, fp)) { 2983edeb0c6SBrian Somers if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) { 2993edeb0c6SBrian Somers len = strlen(buf); 3003edeb0c6SBrian Somers if (len > sizeof wbuf - wlen) { 301dd7e2610SBrian Somers log_Printf(LogWARN, "%s: Can only cope with max file size %d\n", 3023edeb0c6SBrian Somers _PATH_RESCONF, LINE_LEN); 3033edeb0c6SBrian Somers fclose(fp); 3043edeb0c6SBrian Somers return 0; 3053edeb0c6SBrian Somers } 3063edeb0c6SBrian Somers memcpy(wbuf + wlen, buf, len); 3073edeb0c6SBrian Somers wlen += len; 3083edeb0c6SBrian Somers } 3093edeb0c6SBrian Somers } 3103edeb0c6SBrian Somers fclose(fp); 3113edeb0c6SBrian Somers } 3123edeb0c6SBrian Somers 3133edeb0c6SBrian Somers if (addr[0].s_addr != INADDR_ANY) { 3143edeb0c6SBrian Somers snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 3153edeb0c6SBrian Somers inet_ntoa(addr[0])); 316dd7e2610SBrian Somers log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11); 3173edeb0c6SBrian Somers wlen += strlen(wbuf + wlen); 3183edeb0c6SBrian Somers } 3193edeb0c6SBrian Somers 3203edeb0c6SBrian Somers if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) { 3213edeb0c6SBrian Somers snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 3223edeb0c6SBrian Somers inet_ntoa(addr[1])); 323dd7e2610SBrian Somers log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11); 3243edeb0c6SBrian Somers wlen += strlen(wbuf + wlen); 3253edeb0c6SBrian Somers } 3263edeb0c6SBrian Somers 3273edeb0c6SBrian Somers if (wlen) { 3283edeb0c6SBrian Somers int fd; 3293edeb0c6SBrian Somers 3303edeb0c6SBrian Somers if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) { 3313edeb0c6SBrian Somers if (write(fd, wbuf, wlen) != wlen) { 332dd7e2610SBrian Somers log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno)); 3333edeb0c6SBrian Somers close(fd); 3343edeb0c6SBrian Somers return 0; 3353edeb0c6SBrian Somers } 3363edeb0c6SBrian Somers if (ftruncate(fd, wlen) == -1) { 337dd7e2610SBrian Somers log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno)); 3383edeb0c6SBrian Somers close(fd); 3393edeb0c6SBrian Somers return 0; 3403edeb0c6SBrian Somers } 3413edeb0c6SBrian Somers close(fd); 3423edeb0c6SBrian Somers } else { 343dd7e2610SBrian Somers log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno)); 3443edeb0c6SBrian Somers return 0; 3453edeb0c6SBrian Somers } 3463edeb0c6SBrian Somers } 3473edeb0c6SBrian Somers 3483edeb0c6SBrian Somers return 1; 349af57ed9fSAtsushi Murai } 350af57ed9fSAtsushi Murai 351274e766cSBrian Somers int 352dd7e2610SBrian Somers ipcp_Show(struct cmdargs const *arg) 353af57ed9fSAtsushi Murai { 354610b185fSBrian Somers struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 355442f8495SBrian Somers int p; 356af57ed9fSAtsushi Murai 357610b185fSBrian Somers prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, 358610b185fSBrian Somers State2Nam(ipcp->fsm.state)); 359610b185fSBrian Somers if (ipcp->fsm.state == ST_OPENED) { 360b6217683SBrian Somers prompt_Printf(arg->prompt, " His side: %s, %s\n", 361610b185fSBrian Somers inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); 362b6217683SBrian Somers prompt_Printf(arg->prompt, " My side: %s, %s\n", 363610b185fSBrian Somers inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); 364442f8495SBrian Somers prompt_Printf(arg->prompt, " Queued packets: %d\n", ip_QueueLen(ipcp)); 365d1a3ea47SBrian Somers } 3665b4c5b00SBrian Somers 367610b185fSBrian Somers if (ipcp->route) { 368610b185fSBrian Somers prompt_Printf(arg->prompt, "\n"); 369972a1bcfSBrian Somers route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1); 3701ae349f5Scvs2svn } 371927145beSBrian Somers 372b6217683SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 373479508cfSBrian Somers prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 374479508cfSBrian Somers " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout, 375479508cfSBrian Somers ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s", 376479508cfSBrian Somers ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s"); 37750abd4c8SBrian Somers prompt_Printf(arg->prompt, " My Address: %s/%d", 378610b185fSBrian Somers inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width); 379bc76350eSBrian Somers prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask)); 380610b185fSBrian Somers if (ipcp->cfg.HaveTriggerAddress) 381bc76350eSBrian Somers prompt_Printf(arg->prompt, " Trigger address: %s\n", 382610b185fSBrian Somers inet_ntoa(ipcp->cfg.TriggerAddress)); 383bc76350eSBrian Somers 384bc76350eSBrian Somers prompt_Printf(arg->prompt, " VJ compression: %s (%d slots %s slot " 385610b185fSBrian Somers "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), 386610b185fSBrian Somers ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); 38750abd4c8SBrian Somers 388610b185fSBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) 389b6217683SBrian Somers prompt_Printf(arg->prompt, " His Address: %s\n", 390610b185fSBrian Somers ipcp->cfg.peer_list.src); 3911ae349f5Scvs2svn else 392b6217683SBrian Somers prompt_Printf(arg->prompt, " His Address: %s/%d\n", 393610b185fSBrian Somers inet_ntoa(ipcp->cfg.peer_range.ipaddr), 394610b185fSBrian Somers ipcp->cfg.peer_range.width); 39550abd4c8SBrian Somers 3963edeb0c6SBrian Somers prompt_Printf(arg->prompt, " DNS: %s, ", 397610b185fSBrian Somers inet_ntoa(ipcp->cfg.ns.dns[0])); 398610b185fSBrian Somers prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]), 399610b185fSBrian Somers command_ShowNegval(ipcp->cfg.ns.dns_neg)); 4003edeb0c6SBrian Somers prompt_Printf(arg->prompt, " NetBIOS NS: %s, ", 401610b185fSBrian Somers inet_ntoa(ipcp->cfg.ns.nbns[0])); 402610b185fSBrian Somers prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1])); 4031342caedSBrian Somers 404442f8495SBrian Somers prompt_Printf(arg->prompt, " Urgent ports: "); 405442f8495SBrian Somers if (ipcp->cfg.urgent.nports == 0) 406442f8495SBrian Somers prompt_Printf(arg->prompt, "none"); 407442f8495SBrian Somers else 408442f8495SBrian Somers for (p = 0; p < ipcp->cfg.urgent.nports; p++) { 409442f8495SBrian Somers if (p) 410442f8495SBrian Somers prompt_Printf(arg->prompt, ", "); 411442f8495SBrian Somers prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.port[p]); 412442f8495SBrian Somers } 413442f8495SBrian Somers 414442f8495SBrian Somers prompt_Printf(arg->prompt, "\n\n"); 415610b185fSBrian Somers throughput_disp(&ipcp->throughput, arg->prompt); 4169a0b991fSBrian Somers 417927145beSBrian Somers return 0; 418af57ed9fSAtsushi Murai } 419af57ed9fSAtsushi Murai 420d1a3ea47SBrian Somers int 421dd7e2610SBrian Somers ipcp_vjset(struct cmdargs const *arg) 422d1a3ea47SBrian Somers { 42325092092SBrian Somers if (arg->argc != arg->argn+2) 424d1a3ea47SBrian Somers return -1; 42525092092SBrian Somers if (!strcasecmp(arg->argv[arg->argn], "slots")) { 426d1a3ea47SBrian Somers int slots; 427d1a3ea47SBrian Somers 42825092092SBrian Somers slots = atoi(arg->argv[arg->argn+1]); 429d1a3ea47SBrian Somers if (slots < 4 || slots > 16) 430d1a3ea47SBrian Somers return 1; 4311342caedSBrian Somers arg->bundle->ncp.ipcp.cfg.vj.slots = slots; 432d1a3ea47SBrian Somers return 0; 43325092092SBrian Somers } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { 43425092092SBrian Somers if (!strcasecmp(arg->argv[arg->argn+1], "on")) 4351342caedSBrian Somers arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; 43625092092SBrian Somers else if (!strcasecmp(arg->argv[arg->argn+1], "off")) 4371342caedSBrian Somers arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; 438d1a3ea47SBrian Somers else 439d1a3ea47SBrian Somers return 2; 440d1a3ea47SBrian Somers return 0; 441d1a3ea47SBrian Somers } 442d1a3ea47SBrian Somers return -1; 443d1a3ea47SBrian Somers } 444d1a3ea47SBrian Somers 4451ae349f5Scvs2svn void 4466d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, 4476d666775SBrian Somers const struct fsm_parent *parent) 448d1a3ea47SBrian Somers { 449503a7782SBrian Somers struct hostent *hp; 450503a7782SBrian Somers char name[MAXHOSTNAMELEN]; 4513b0f8d2eSBrian Somers static const char *timer_names[] = 4523b0f8d2eSBrian Somers {"IPCP restart", "IPCP openmode", "IPCP stopped"}; 45329e275ceSBrian Somers 454479508cfSBrian Somers fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP, 4553b0f8d2eSBrian Somers bundle, l, parent, &ipcp_Callbacks, timer_names); 456503a7782SBrian Somers 457610b185fSBrian Somers ipcp->route = NULL; 4581342caedSBrian Somers ipcp->cfg.vj.slots = DEF_VJ_STATES; 4591342caedSBrian Somers ipcp->cfg.vj.slotcomp = 1; 460503a7782SBrian Somers memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 461503a7782SBrian Somers if (gethostname(name, sizeof name) == 0) { 462503a7782SBrian Somers hp = gethostbyname(name); 4638fa6ebe4SBrian Somers if (hp && hp->h_addrtype == AF_INET) 464503a7782SBrian Somers memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); 465503a7782SBrian Somers } 46630c2f2ffSBrian Somers ipcp->cfg.netmask.s_addr = INADDR_ANY; 467503a7782SBrian Somers memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 468503a7782SBrian Somers iplist_setsrc(&ipcp->cfg.peer_list, ""); 469503a7782SBrian Somers ipcp->cfg.HaveTriggerAddress = 0; 470503a7782SBrian Somers 4713edeb0c6SBrian Somers ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY; 4723edeb0c6SBrian Somers ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY; 4733edeb0c6SBrian Somers ipcp->cfg.ns.dns_neg = 0; 4743edeb0c6SBrian Somers ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; 4753edeb0c6SBrian Somers ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; 476cd9647a1SBrian Somers 477442f8495SBrian Somers ipcp->cfg.urgent.nports = ipcp->cfg.urgent.maxports = NDEFPORTS; 478442f8495SBrian Somers ipcp->cfg.urgent.port = (u_short *)malloc(NDEFPORTS * sizeof(u_short)); 479442f8495SBrian Somers memcpy(ipcp->cfg.urgent.port, default_urgent_ports, 480442f8495SBrian Somers NDEFPORTS * sizeof(u_short)); 481442f8495SBrian Somers 482479508cfSBrian Somers ipcp->cfg.fsm.timeout = DEF_FSMRETRY; 483479508cfSBrian Somers ipcp->cfg.fsm.maxreq = DEF_FSMTRIES; 484479508cfSBrian Somers ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES; 4851342caedSBrian Somers ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; 486503a7782SBrian Somers 487eaa4df37SBrian Somers memset(&ipcp->vj, '\0', sizeof ipcp->vj); 488eaa4df37SBrian Somers 489ab2de065SBrian Somers throughput_init(&ipcp->throughput, SAMPLE_PERIOD); 4905a72b6edSBrian Somers memset(ipcp->Queue, '\0', sizeof ipcp->Queue); 491972a1bcfSBrian Somers ipcp_Setup(ipcp, INADDR_NONE); 492d1a3ea47SBrian Somers } 493d1a3ea47SBrian Somers 494af57ed9fSAtsushi Murai void 495442f8495SBrian Somers ipcp_Destroy(struct ipcp *ipcp) 496442f8495SBrian Somers { 497442f8495SBrian Somers if (ipcp->cfg.urgent.maxports) { 498442f8495SBrian Somers ipcp->cfg.urgent.nports = ipcp->cfg.urgent.maxports = 0; 499442f8495SBrian Somers free(ipcp->cfg.urgent.port); 500442f8495SBrian Somers ipcp->cfg.urgent.port = NULL; 501442f8495SBrian Somers } 502442f8495SBrian Somers } 503442f8495SBrian Somers 504442f8495SBrian Somers void 505ce828a6eSBrian Somers ipcp_SetLink(struct ipcp *ipcp, struct link *l) 506af57ed9fSAtsushi Murai { 507ce828a6eSBrian Somers ipcp->fsm.link = l; 508af57ed9fSAtsushi Murai } 509549d663dSAtsushi Murai 510ce828a6eSBrian Somers void 511972a1bcfSBrian Somers ipcp_Setup(struct ipcp *ipcp, u_int32_t mask) 512503a7782SBrian Somers { 5138fa6ebe4SBrian Somers struct iface *iface = ipcp->fsm.bundle->iface; 5148fa6ebe4SBrian Somers int pos, n; 515503a7782SBrian Somers 516503a7782SBrian Somers ipcp->fsm.open_mode = 0; 517972a1bcfSBrian Somers ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask; 518503a7782SBrian Somers 519503a7782SBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 5208fa6ebe4SBrian Somers /* Try to give the peer a previously configured IP address */ 5218fa6ebe4SBrian Somers for (n = 0; n < iface->in_addrs; n++) { 5228fa6ebe4SBrian Somers pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd); 5238fa6ebe4SBrian Somers if (pos != -1) { 5248fa6ebe4SBrian Somers ipcp->cfg.peer_range.ipaddr = 5258fa6ebe4SBrian Somers iplist_setcurpos(&ipcp->cfg.peer_list, pos); 5268fa6ebe4SBrian Somers break; 5278fa6ebe4SBrian Somers } 5288fa6ebe4SBrian Somers } 5298fa6ebe4SBrian Somers if (n == iface->in_addrs) 5308fa6ebe4SBrian Somers /* Ok, so none of 'em fit.... pick a random one */ 531503a7782SBrian Somers ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); 5328fa6ebe4SBrian Somers 533503a7782SBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 534503a7782SBrian Somers ipcp->cfg.peer_range.width = 32; 535503a7782SBrian Somers } 536503a7782SBrian Somers 537503a7782SBrian Somers ipcp->heis1172 = 0; 538503a7782SBrian Somers 539503a7782SBrian Somers ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; 540503a7782SBrian Somers ipcp->peer_compproto = 0; 5411ae349f5Scvs2svn 5428390b576SBrian Somers if (ipcp->cfg.HaveTriggerAddress) { 543549d663dSAtsushi Murai /* 5445b4c5b00SBrian Somers * Some implementations of PPP require that we send a 5455b4c5b00SBrian Somers * *special* value as our address, even though the rfc specifies 5465b4c5b00SBrian Somers * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 547549d663dSAtsushi Murai */ 548503a7782SBrian Somers ipcp->my_ip = ipcp->cfg.TriggerAddress; 549dd7e2610SBrian Somers log_Printf(LogIPCP, "Using trigger address %s\n", 550503a7782SBrian Somers inet_ntoa(ipcp->cfg.TriggerAddress)); 5518fa6ebe4SBrian Somers } else { 5528390b576SBrian Somers /* 5538fa6ebe4SBrian Somers * Otherwise, if we've used an IP number before and it's still within 5548fa6ebe4SBrian Somers * the network specified on the ``set ifaddr'' line, we really 5558fa6ebe4SBrian Somers * want to keep that IP number so that we can keep any existing 5568fa6ebe4SBrian Somers * connections that are bound to that IP (assuming we're not 5578fa6ebe4SBrian Somers * ``iface-alias''ing). 5588390b576SBrian Somers */ 5598fa6ebe4SBrian Somers for (n = 0; n < iface->in_addrs; n++) 5608fa6ebe4SBrian Somers if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) == 5618fa6ebe4SBrian Somers (ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) { 5628fa6ebe4SBrian Somers ipcp->my_ip = iface->in_addr[n].ifa; 5638fa6ebe4SBrian Somers break; 5648fa6ebe4SBrian Somers } 5658fa6ebe4SBrian Somers if (n == iface->in_addrs) 566503a7782SBrian Somers ipcp->my_ip = ipcp->cfg.my_range.ipaddr; 5678fa6ebe4SBrian Somers } 56829e275ceSBrian Somers 569972a1bcfSBrian Somers if (IsEnabled(ipcp->cfg.vj.neg) 570972a1bcfSBrian Somers #ifndef NORADIUS 571972a1bcfSBrian Somers || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj) 572972a1bcfSBrian Somers #endif 573972a1bcfSBrian Somers ) 574503a7782SBrian Somers ipcp->my_compproto = (PROTO_VJCOMP << 16) + 5751342caedSBrian Somers ((ipcp->cfg.vj.slots - 1) << 8) + 5761342caedSBrian Somers ipcp->cfg.vj.slotcomp; 5771ae349f5Scvs2svn else 578503a7782SBrian Somers ipcp->my_compproto = 0; 5791342caedSBrian Somers sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); 58029e275ceSBrian Somers 581503a7782SBrian Somers ipcp->peer_reject = 0; 582503a7782SBrian Somers ipcp->my_reject = 0; 5831ae349f5Scvs2svn } 5841ae349f5Scvs2svn 585455aabc3SBrian Somers static int 5863afe5ccbSBrian Somers ipcp_doproxyall(struct bundle *bundle, 5873afe5ccbSBrian Somers int (*proxyfun)(struct bundle *, struct in_addr, int), int s) 5883afe5ccbSBrian Somers { 5893afe5ccbSBrian Somers int n, ret; 5903afe5ccbSBrian Somers struct sticky_route *rp; 5913afe5ccbSBrian Somers struct in_addr addr; 5923afe5ccbSBrian Somers struct ipcp *ipcp; 5933afe5ccbSBrian Somers 5943afe5ccbSBrian Somers ipcp = &bundle->ncp.ipcp; 5953afe5ccbSBrian Somers for (rp = ipcp->route; rp != NULL; rp = rp->next) { 596bc76350eSBrian Somers if (rp->mask.s_addr == INADDR_BROADCAST) 5973afe5ccbSBrian Somers continue; 598bc76350eSBrian Somers n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1; 5993afe5ccbSBrian Somers if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) { 6003afe5ccbSBrian Somers addr = rp->dst; 6013afe5ccbSBrian Somers while (n--) { 6023afe5ccbSBrian Somers addr.s_addr = htonl(ntohl(addr.s_addr) + 1); 6033afe5ccbSBrian Somers log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr)); 6043afe5ccbSBrian Somers ret = (*proxyfun)(bundle, addr, s); 6053afe5ccbSBrian Somers if (!ret) 6063afe5ccbSBrian Somers return ret; 6073afe5ccbSBrian Somers } 6083afe5ccbSBrian Somers } 6093afe5ccbSBrian Somers } 6103afe5ccbSBrian Somers 6113afe5ccbSBrian Somers return 0; 6123afe5ccbSBrian Somers } 6133afe5ccbSBrian Somers 6143afe5ccbSBrian Somers static int 61530c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, 61630c2f2ffSBrian Somers struct in_addr hisaddr, int silent) 617455aabc3SBrian Somers { 61868645f39SBrian Somers struct in_addr mask, oaddr, none = { INADDR_ANY }; 619455aabc3SBrian Somers 620bc76350eSBrian Somers mask = addr2mask(myaddr); 621455aabc3SBrian Somers 622972a1bcfSBrian Somers if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY && 623bc76350eSBrian Somers (bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr) 624bc76350eSBrian Somers mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr; 625455aabc3SBrian Somers 6268fa6ebe4SBrian Somers oaddr.s_addr = bundle->iface->in_addrs ? 6278fa6ebe4SBrian Somers bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY; 6288fa6ebe4SBrian Somers if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr, 6298fa6ebe4SBrian Somers IFACE_ADD_FIRST|IFACE_FORCE_ADD)) 6308fa6ebe4SBrian Somers return -1; 631455aabc3SBrian Somers 6328fa6ebe4SBrian Somers if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1 6338fa6ebe4SBrian Somers && myaddr.s_addr != oaddr.s_addr) 6348fa6ebe4SBrian Somers /* Nuke the old one */ 6358fa6ebe4SBrian Somers iface_inDelete(bundle->iface, oaddr); 636455aabc3SBrian Somers 6373afe5ccbSBrian Somers if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0) 6383afe5ccbSBrian Somers bundle_SetRoute(bundle, RTM_CHANGE, hisaddr, myaddr, none, 0, 0); 6393afe5ccbSBrian Somers 640610b185fSBrian Somers if (Enabled(bundle, OPT_SROUTES)) 641610b185fSBrian Somers route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); 642610b185fSBrian Somers 643972a1bcfSBrian Somers #ifndef NORADIUS 644972a1bcfSBrian Somers if (bundle->radius.valid) 645972a1bcfSBrian Somers route_Change(bundle, bundle->radius.routes, myaddr, hisaddr); 646972a1bcfSBrian Somers #endif 647972a1bcfSBrian Somers 6483afe5ccbSBrian Somers if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) { 6498fa6ebe4SBrian Somers int s = ID0socket(AF_INET, SOCK_DGRAM, 0); 6508fa6ebe4SBrian Somers if (s < 0) 6518fa6ebe4SBrian Somers log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n", 6528fa6ebe4SBrian Somers strerror(errno)); 6538fa6ebe4SBrian Somers else { 6543afe5ccbSBrian Somers if (Enabled(bundle, OPT_PROXYALL)) 6553afe5ccbSBrian Somers ipcp_doproxyall(bundle, arp_SetProxy, s); 6563afe5ccbSBrian Somers else if (Enabled(bundle, OPT_PROXY)) 6578fa6ebe4SBrian Somers arp_SetProxy(bundle, hisaddr, s); 658455aabc3SBrian Somers close(s); 6598fa6ebe4SBrian Somers } 6608fa6ebe4SBrian Somers } 6618fa6ebe4SBrian Somers 6628fa6ebe4SBrian Somers return 0; 663455aabc3SBrian Somers } 664455aabc3SBrian Somers 665455aabc3SBrian Somers static struct in_addr 6668fa6ebe4SBrian Somers ChooseHisAddr(struct bundle *bundle, struct in_addr gw) 667455aabc3SBrian Somers { 668455aabc3SBrian Somers struct in_addr try; 6693a2e4f62SBrian Somers u_long f; 670455aabc3SBrian Somers 6715828db6dSBrian Somers for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { 6725828db6dSBrian Somers try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); 6733a2e4f62SBrian Somers log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n", 674455aabc3SBrian Somers f, inet_ntoa(try)); 67530c2f2ffSBrian Somers if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { 676dd7e2610SBrian Somers log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); 677455aabc3SBrian Somers break; 678455aabc3SBrian Somers } 679455aabc3SBrian Somers } 680455aabc3SBrian Somers 6815828db6dSBrian Somers if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { 682dd7e2610SBrian Somers log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 683455aabc3SBrian Somers try.s_addr = INADDR_ANY; 684455aabc3SBrian Somers } 685455aabc3SBrian Somers 686455aabc3SBrian Somers return try; 687af57ed9fSAtsushi Murai } 688af57ed9fSAtsushi Murai 689af57ed9fSAtsushi Murai static void 690479508cfSBrian Somers IpcpInitRestartCounter(struct fsm *fp, int what) 691af57ed9fSAtsushi Murai { 6927308ec68SBrian Somers /* Set fsm timer load */ 693cd9647a1SBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 694cd9647a1SBrian Somers 695479508cfSBrian Somers fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS; 696479508cfSBrian Somers switch (what) { 697479508cfSBrian Somers case FSM_REQ_TIMER: 698479508cfSBrian Somers fp->restart = ipcp->cfg.fsm.maxreq; 699479508cfSBrian Somers break; 700479508cfSBrian Somers case FSM_TRM_TIMER: 701479508cfSBrian Somers fp->restart = ipcp->cfg.fsm.maxtrm; 702479508cfSBrian Somers break; 703479508cfSBrian Somers default: 704479508cfSBrian Somers fp->restart = 1; 705479508cfSBrian Somers break; 706479508cfSBrian Somers } 707af57ed9fSAtsushi Murai } 708af57ed9fSAtsushi Murai 709af57ed9fSAtsushi Murai static void 710944f7098SBrian Somers IpcpSendConfigReq(struct fsm *fp) 711af57ed9fSAtsushi Murai { 7127308ec68SBrian Somers /* Send config REQ please */ 7138c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 714aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 7153edeb0c6SBrian Somers u_char buff[24]; 7162267893fSBrian Somers struct lcp_opt *o; 717af57ed9fSAtsushi Murai 7182267893fSBrian Somers o = (struct lcp_opt *)buff; 71930c2f2ffSBrian Somers 720dd7e2610SBrian Somers if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 7219e8ec64bSBrian Somers memcpy(o->data, &ipcp->my_ip.s_addr, 4); 7222267893fSBrian Somers INC_LCP_OPT(TY_IPADDR, 6, o); 7230053cc58SBrian Somers } 7240053cc58SBrian Somers 725e43ebac1SBrian Somers if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 72683d1af55SBrian Somers if (ipcp->heis1172) { 7279e8ec64bSBrian Somers u_int16_t proto = PROTO_VJCOMP; 7289e8ec64bSBrian Somers 7299e8ec64bSBrian Somers ua_htons(&proto, o->data); 7302267893fSBrian Somers INC_LCP_OPT(TY_COMPPROTO, 4, o); 7310053cc58SBrian Somers } else { 7327686a200SBrian Somers struct compreq req; 7337686a200SBrian Somers 7347686a200SBrian Somers req.proto = htons(ipcp->my_compproto >> 16); 7357686a200SBrian Somers req.slots = (ipcp->my_compproto >> 8) & 255; 7367686a200SBrian Somers req.compcid = ipcp->my_compproto & 1; 7377686a200SBrian Somers memcpy(o->data, &req, 4); 7382267893fSBrian Somers INC_LCP_OPT(TY_COMPPROTO, 6, o); 7390053cc58SBrian Somers } 740af57ed9fSAtsushi Murai } 7412267893fSBrian Somers 7423edeb0c6SBrian Somers if (IsEnabled(ipcp->cfg.ns.dns_neg) && 7433edeb0c6SBrian Somers !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && 7443edeb0c6SBrian Somers !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { 7453edeb0c6SBrian Somers struct in_addr dns[2]; 7463edeb0c6SBrian Somers getdns(ipcp, dns); 7479e8ec64bSBrian Somers memcpy(o->data, &dns[0].s_addr, 4); 7483edeb0c6SBrian Somers INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); 7499e8ec64bSBrian Somers memcpy(o->data, &dns[1].s_addr, 4); 7503edeb0c6SBrian Somers INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); 7513edeb0c6SBrian Somers } 7523edeb0c6SBrian Somers 753411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 754411675baSBrian Somers MB_IPCPOUT); 755af57ed9fSAtsushi Murai } 756af57ed9fSAtsushi Murai 757af57ed9fSAtsushi Murai static void 7582267893fSBrian Somers IpcpSentTerminateReq(struct fsm *fp) 759af57ed9fSAtsushi Murai { 7607308ec68SBrian Somers /* Term REQ just sent by FSM */ 761af57ed9fSAtsushi Murai } 762af57ed9fSAtsushi Murai 763af57ed9fSAtsushi Murai static void 7642267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id) 765af57ed9fSAtsushi Murai { 7667308ec68SBrian Somers /* Send Term ACK please */ 767411675baSBrian Somers fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT); 768af57ed9fSAtsushi Murai } 769af57ed9fSAtsushi Murai 770af57ed9fSAtsushi Murai static void 771944f7098SBrian Somers IpcpLayerStart(struct fsm *fp) 772af57ed9fSAtsushi Murai { 7737308ec68SBrian Somers /* We're about to start up ! */ 774897f9429SBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 775897f9429SBrian Somers 7763a2e4f62SBrian Somers log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name); 777897f9429SBrian Somers throughput_start(&ipcp->throughput, "IPCP throughput", 778897f9429SBrian Somers Enabled(fp->bundle, OPT_THROUGHPUT)); 779479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 780af57ed9fSAtsushi Murai } 781af57ed9fSAtsushi Murai 782af57ed9fSAtsushi Murai static void 783944f7098SBrian Somers IpcpLayerFinish(struct fsm *fp) 784af57ed9fSAtsushi Murai { 7857308ec68SBrian Somers /* We're now down */ 786897f9429SBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 787897f9429SBrian Somers 7883a2e4f62SBrian Somers log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name); 789897f9429SBrian Somers throughput_stop(&ipcp->throughput); 790897f9429SBrian Somers throughput_log(&ipcp->throughput, LogIPCP, NULL); 7911ae349f5Scvs2svn } 7921ae349f5Scvs2svn 79368a0f0ccSBrian Somers void 794dd7e2610SBrian Somers ipcp_CleanInterface(struct ipcp *ipcp) 79568a0f0ccSBrian Somers { 7968fa6ebe4SBrian Somers struct iface *iface = ipcp->fsm.bundle->iface; 79768a0f0ccSBrian Somers 798610b185fSBrian Somers route_Clean(ipcp->fsm.bundle, ipcp->route); 799610b185fSBrian Somers 8003afe5ccbSBrian Somers if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) || 8013afe5ccbSBrian Somers Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) { 8028fa6ebe4SBrian Somers int s = ID0socket(AF_INET, SOCK_DGRAM, 0); 8038fa6ebe4SBrian Somers if (s < 0) 8048fa6ebe4SBrian Somers log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", 80568a0f0ccSBrian Somers strerror(errno)); 8068fa6ebe4SBrian Somers else { 8073afe5ccbSBrian Somers if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL)) 8083afe5ccbSBrian Somers ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s); 8093afe5ccbSBrian Somers else if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) 8108fa6ebe4SBrian Somers arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s); 8118fa6ebe4SBrian Somers close(s); 8128fa6ebe4SBrian Somers } 81368a0f0ccSBrian Somers } 81468a0f0ccSBrian Somers 8158fa6ebe4SBrian Somers iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL); 816af57ed9fSAtsushi Murai } 817af57ed9fSAtsushi Murai 818af57ed9fSAtsushi Murai static void 819944f7098SBrian Somers IpcpLayerDown(struct fsm *fp) 820af57ed9fSAtsushi Murai { 8217308ec68SBrian Somers /* About to come down */ 822aa857470SBrian Somers static int recursing; 823aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 824455aabc3SBrian Somers const char *s; 825455aabc3SBrian Somers 826aa857470SBrian Somers if (!recursing++) { 8278fa6ebe4SBrian Somers if (ipcp->fsm.bundle->iface->in_addrs) 8288fa6ebe4SBrian Somers s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa); 8298fa6ebe4SBrian Somers else 8308fa6ebe4SBrian Somers s = "Interface configuration error !"; 8313a2e4f62SBrian Somers log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s); 832455aabc3SBrian Somers 833455aabc3SBrian Somers /* 834455aabc3SBrian Somers * XXX this stuff should really live in the FSM. Our config should 835455aabc3SBrian Somers * associate executable sections in files with events. 836455aabc3SBrian Somers */ 83730291ffbSBrian Somers if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) { 83849052c95SBrian Somers if (bundle_GetLabel(fp->bundle)) { 839dd7e2610SBrian Somers if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 84030291ffbSBrian Somers LINKDOWNFILE, NULL, NULL) < 0) 84130291ffbSBrian Somers system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 842455aabc3SBrian Somers } else 84330291ffbSBrian Somers system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 844af57ed9fSAtsushi Murai } 845af57ed9fSAtsushi Murai 846972a1bcfSBrian Somers ipcp_Setup(ipcp, INADDR_NONE); 8471ae349f5Scvs2svn } 848aa857470SBrian Somers recursing--; 849aa857470SBrian Somers } 8501ae349f5Scvs2svn 851dd0645c5SBrian Somers int 852dd0645c5SBrian Somers ipcp_InterfaceUp(struct ipcp *ipcp) 853dd0645c5SBrian Somers { 854dd0645c5SBrian Somers if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { 855a33b2ef7SBrian Somers log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n"); 856dd0645c5SBrian Somers return 0; 857dd0645c5SBrian Somers } 858dd0645c5SBrian Somers 85967b072f7SBrian Somers #ifndef NONAT 86067b072f7SBrian Somers if (ipcp->fsm.bundle->NatEnabled) 861615ad4f9SBrian Somers PacketAliasSetAddress(ipcp->my_ip); 862dd0645c5SBrian Somers #endif 863dd0645c5SBrian Somers 864dd0645c5SBrian Somers return 1; 865dd0645c5SBrian Somers } 866dd0645c5SBrian Somers 8676f384573SBrian Somers static int 868944f7098SBrian Somers IpcpLayerUp(struct fsm *fp) 869af57ed9fSAtsushi Murai { 8707308ec68SBrian Somers /* We're now up */ 871aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 8728fa6ebe4SBrian Somers char tbuff[16]; 873af57ed9fSAtsushi Murai 8743a2e4f62SBrian Somers log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name); 8758fa6ebe4SBrian Somers snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip)); 8768fa6ebe4SBrian Somers log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n", 8778fa6ebe4SBrian Somers tbuff, inet_ntoa(ipcp->peer_ip)); 87803604f35SBrian Somers 879503a7782SBrian Somers if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 880eaa4df37SBrian Somers sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); 88103604f35SBrian Somers 882dd0645c5SBrian Somers if (!ipcp_InterfaceUp(ipcp)) 8836f384573SBrian Somers return 0; 884455aabc3SBrian Somers 885455aabc3SBrian Somers /* 886455aabc3SBrian Somers * XXX this stuff should really live in the FSM. Our config should 887455aabc3SBrian Somers * associate executable sections in files with events. 888455aabc3SBrian Somers */ 8898fa6ebe4SBrian Somers if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 89049052c95SBrian Somers if (bundle_GetLabel(fp->bundle)) { 891dd7e2610SBrian Somers if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 89230291ffbSBrian Somers LINKUPFILE, NULL, NULL) < 0) 89330291ffbSBrian Somers system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 894455aabc3SBrian Somers } else 89530291ffbSBrian Somers system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 896af57ed9fSAtsushi Murai } 897af57ed9fSAtsushi Murai 898479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 8990f2f3eb3SBrian Somers log_DisplayPrompts(); 900479508cfSBrian Somers 9016f384573SBrian Somers return 1; 902af57ed9fSAtsushi Murai } 903af57ed9fSAtsushi Murai 904af57ed9fSAtsushi Murai static int 9058fa6ebe4SBrian Somers AcceptableAddr(const struct in_range *prange, struct in_addr ipaddr) 906af57ed9fSAtsushi Murai { 9077308ec68SBrian Somers /* Is the given IP in the given range ? */ 908057df964SBrian Somers return (prange->ipaddr.s_addr & prange->mask.s_addr) == 909057df964SBrian Somers (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 910af57ed9fSAtsushi Murai } 911af57ed9fSAtsushi Murai 912af57ed9fSAtsushi Murai static void 91330c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 91430c2f2ffSBrian Somers struct fsm_decode *dec) 915af57ed9fSAtsushi Murai { 9167308ec68SBrian Somers /* Deal with incoming PROTO_IPCP */ 9178fa6ebe4SBrian Somers struct iface *iface = fp->bundle->iface; 918aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 9198fa6ebe4SBrian Somers int type, length, gotdns, gotdnsnak, n; 920fe3125a0SBrian Somers u_int32_t compproto; 921af57ed9fSAtsushi Murai struct compreq *pcomp; 9223edeb0c6SBrian Somers struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; 92330c2f2ffSBrian Somers char tbuff[100], tbuff2[100]; 924af57ed9fSAtsushi Murai 9253edeb0c6SBrian Somers gotdns = 0; 9263edeb0c6SBrian Somers gotdnsnak = 0; 9273edeb0c6SBrian Somers dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; 928af57ed9fSAtsushi Murai 929af57ed9fSAtsushi Murai while (plen >= sizeof(struct fsmconfig)) { 930af57ed9fSAtsushi Murai type = *cp; 931af57ed9fSAtsushi Murai length = cp[1]; 932d47dceb8SBrian Somers 933d47dceb8SBrian Somers if (length == 0) { 934dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); 935d47dceb8SBrian Somers break; 936d47dceb8SBrian Somers } 937d47dceb8SBrian Somers 9389e836af5SBrian Somers if (type < NCFTYPES) 93970ee81ffSBrian Somers snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); 9409e836af5SBrian Somers else if (type > 128 && type < 128 + NCFTYPES128) 94170ee81ffSBrian Somers snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); 942af57ed9fSAtsushi Murai else 94370ee81ffSBrian Somers snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); 944af57ed9fSAtsushi Murai 945af57ed9fSAtsushi Murai switch (type) { 946af57ed9fSAtsushi Murai case TY_IPADDR: /* RFC1332 */ 9479e8ec64bSBrian Somers memcpy(&ipaddr.s_addr, cp + 2, 4); 948dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 949af57ed9fSAtsushi Murai 9509780ef31SBrian Somers switch (mode_type) { 951af57ed9fSAtsushi Murai case MODE_REQ: 952503a7782SBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 953f5fb6bd0SBrian Somers if (ipaddr.s_addr == INADDR_ANY || 954503a7782SBrian Somers iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || 95530c2f2ffSBrian Somers ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, 95630c2f2ffSBrian Somers ipaddr, 1)) { 957dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: Address invalid or already in use\n", 958bcc332bdSBrian Somers inet_ntoa(ipaddr)); 9598390b576SBrian Somers /* 9608fa6ebe4SBrian Somers * If we've already had a valid address configured for the peer, 9618fa6ebe4SBrian Somers * try NAKing with that so that we don't have to upset things 9628fa6ebe4SBrian Somers * too much. 9638390b576SBrian Somers */ 9648fa6ebe4SBrian Somers for (n = 0; n < iface->in_addrs; n++) 9658fa6ebe4SBrian Somers if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd) 9668fa6ebe4SBrian Somers >=0) { 9678fa6ebe4SBrian Somers ipcp->peer_ip = iface->in_addr[n].brd; 9688fa6ebe4SBrian Somers break; 9698fa6ebe4SBrian Somers } 9708fa6ebe4SBrian Somers 9718fa6ebe4SBrian Somers if (n == iface->in_addrs) 9728390b576SBrian Somers /* Just pick an IP number from our list */ 973503a7782SBrian Somers ipcp->peer_ip = ChooseHisAddr 97430c2f2ffSBrian Somers (fp->bundle, ipcp->cfg.my_range.ipaddr); 9758390b576SBrian Somers 976503a7782SBrian Somers if (ipcp->peer_ip.s_addr == INADDR_ANY) { 97730c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 97830c2f2ffSBrian Somers dec->rejend += length; 979bcc332bdSBrian Somers } else { 98030c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 98130c2f2ffSBrian Somers memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2); 98230c2f2ffSBrian Somers dec->nakend += length; 983bcc332bdSBrian Somers } 984bcc332bdSBrian Somers break; 985bcc332bdSBrian Somers } 986503a7782SBrian Somers } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { 987af57ed9fSAtsushi Murai /* 9888390b576SBrian Somers * If destination address is not acceptable, NAK with what we 989944f7098SBrian Somers * want to use. 990af57ed9fSAtsushi Murai */ 99130c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 9928fa6ebe4SBrian Somers for (n = 0; n < iface->in_addrs; n++) 9938fa6ebe4SBrian Somers if ((iface->in_addr[n].brd.s_addr & 9948fa6ebe4SBrian Somers ipcp->cfg.peer_range.mask.s_addr) 9958fa6ebe4SBrian Somers == (ipcp->cfg.peer_range.ipaddr.s_addr & 9968fa6ebe4SBrian Somers ipcp->cfg.peer_range.mask.s_addr)) { 9978390b576SBrian Somers /* We prefer the already-configured address */ 9988fa6ebe4SBrian Somers memcpy(dec->nakend + 2, &iface->in_addr[n].brd.s_addr, 9998fa6ebe4SBrian Somers length - 2); 10008fa6ebe4SBrian Somers break; 10018fa6ebe4SBrian Somers } 10028fa6ebe4SBrian Somers 10038fa6ebe4SBrian Somers if (n == iface->in_addrs) 100430c2f2ffSBrian Somers memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2); 10058fa6ebe4SBrian Somers 100630c2f2ffSBrian Somers dec->nakend += length; 1007af57ed9fSAtsushi Murai break; 1008af57ed9fSAtsushi Murai } 1009503a7782SBrian Somers ipcp->peer_ip = ipaddr; 101030c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 101130c2f2ffSBrian Somers dec->ackend += length; 1012af57ed9fSAtsushi Murai break; 10138fa6ebe4SBrian Somers 1014af57ed9fSAtsushi Murai case MODE_NAK: 1015503a7782SBrian Somers if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { 1016bcc332bdSBrian Somers /* Use address suggested by peer */ 101770ee81ffSBrian Somers snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 1018503a7782SBrian Somers inet_ntoa(ipcp->my_ip)); 1019dd7e2610SBrian Somers log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 1020503a7782SBrian Somers ipcp->my_ip = ipaddr; 10211d1fc017SBrian Somers bundle_AdjustFilters(fp->bundle, &ipcp->my_ip, NULL); 1022bcc332bdSBrian Somers } else { 1023dd7e2610SBrian Somers log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, 10248390b576SBrian Somers "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 1025dd7e2610SBrian Somers fsm_Close(&ipcp->fsm); 1026af57ed9fSAtsushi Murai } 1027af57ed9fSAtsushi Murai break; 10288fa6ebe4SBrian Somers 1029af57ed9fSAtsushi Murai case MODE_REJ: 1030503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 1031af57ed9fSAtsushi Murai break; 1032af57ed9fSAtsushi Murai } 1033af57ed9fSAtsushi Murai break; 10348fa6ebe4SBrian Somers 1035af57ed9fSAtsushi Murai case TY_COMPPROTO: 10367686a200SBrian Somers pcomp = (struct compreq *)(cp + 2); 10377686a200SBrian Somers compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 10387686a200SBrian Somers pcomp->compcid; 1039dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 1040af57ed9fSAtsushi Murai 10419780ef31SBrian Somers switch (mode_type) { 1042af57ed9fSAtsushi Murai case MODE_REQ: 10431342caedSBrian Somers if (!IsAccepted(ipcp->cfg.vj.neg)) { 104430c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 104530c2f2ffSBrian Somers dec->rejend += length; 1046af57ed9fSAtsushi Murai } else { 1047af57ed9fSAtsushi Murai switch (length) { 1048af57ed9fSAtsushi Murai case 4: /* RFC1172 */ 1049af57ed9fSAtsushi Murai if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 10507686a200SBrian Somers log_Printf(LogWARN, "Peer is speaking RFC1172 compression " 10517686a200SBrian Somers "protocol !\n"); 105283d1af55SBrian Somers ipcp->heis1172 = 1; 1053503a7782SBrian Somers ipcp->peer_compproto = compproto; 105430c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 105530c2f2ffSBrian Somers dec->ackend += length; 1056af57ed9fSAtsushi Murai } else { 105730c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 1058af57ed9fSAtsushi Murai pcomp->proto = htons(PROTO_VJCOMP); 105930c2f2ffSBrian Somers memcpy(dec->nakend+2, &pcomp, 2); 106030c2f2ffSBrian Somers dec->nakend += length; 1061af57ed9fSAtsushi Murai } 1062af57ed9fSAtsushi Murai break; 1063af57ed9fSAtsushi Murai case 6: /* RFC1332 */ 10647686a200SBrian Somers if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 10657686a200SBrian Somers if (pcomp->slots <= MAX_VJ_STATES 1066503a7782SBrian Somers && pcomp->slots >= MIN_VJ_STATES) { 10677686a200SBrian Somers /* Ok, we can do that */ 1068503a7782SBrian Somers ipcp->peer_compproto = compproto; 106983d1af55SBrian Somers ipcp->heis1172 = 0; 107030c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 107130c2f2ffSBrian Somers dec->ackend += length; 1072af57ed9fSAtsushi Murai } else { 10737686a200SBrian Somers /* Get as close as we can to what he wants */ 10747686a200SBrian Somers ipcp->heis1172 = 0; 10757686a200SBrian Somers memcpy(dec->nakend, cp, 2); 10767686a200SBrian Somers pcomp->slots = pcomp->slots < MIN_VJ_STATES ? 10777686a200SBrian Somers MIN_VJ_STATES : MAX_VJ_STATES; 10787686a200SBrian Somers memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 10797686a200SBrian Somers dec->nakend += length; 10807686a200SBrian Somers } 10817686a200SBrian Somers } else { 10827686a200SBrian Somers /* What we really want */ 108330c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 1084af57ed9fSAtsushi Murai pcomp->proto = htons(PROTO_VJCOMP); 1085503a7782SBrian Somers pcomp->slots = DEF_VJ_STATES; 10867686a200SBrian Somers pcomp->compcid = 1; 108730c2f2ffSBrian Somers memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 108830c2f2ffSBrian Somers dec->nakend += length; 1089af57ed9fSAtsushi Murai } 1090af57ed9fSAtsushi Murai break; 1091af57ed9fSAtsushi Murai default: 109230c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 109330c2f2ffSBrian Somers dec->rejend += length; 1094af57ed9fSAtsushi Murai break; 1095af57ed9fSAtsushi Murai } 1096af57ed9fSAtsushi Murai } 1097af57ed9fSAtsushi Murai break; 10988fa6ebe4SBrian Somers 1099af57ed9fSAtsushi Murai case MODE_NAK: 11007686a200SBrian Somers if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 11017686a200SBrian Somers if (pcomp->slots > MAX_VJ_STATES) 11027686a200SBrian Somers pcomp->slots = MAX_VJ_STATES; 11037686a200SBrian Somers else if (pcomp->slots < MIN_VJ_STATES) 11047686a200SBrian Somers pcomp->slots = MIN_VJ_STATES; 11057686a200SBrian Somers compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 11067686a200SBrian Somers pcomp->compcid; 11077686a200SBrian Somers } else 11087686a200SBrian Somers compproto = 0; 1109dd7e2610SBrian Somers log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 1110503a7782SBrian Somers tbuff, ipcp->my_compproto, compproto); 1111503a7782SBrian Somers ipcp->my_compproto = compproto; 1112af57ed9fSAtsushi Murai break; 11138fa6ebe4SBrian Somers 1114af57ed9fSAtsushi Murai case MODE_REJ: 1115503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 1116af57ed9fSAtsushi Murai break; 1117af57ed9fSAtsushi Murai } 1118af57ed9fSAtsushi Murai break; 11198fa6ebe4SBrian Somers 1120af57ed9fSAtsushi Murai case TY_IPADDRS: /* RFC1172 */ 11219e8ec64bSBrian Somers memcpy(&ipaddr.s_addr, cp + 2, 4); 11229e8ec64bSBrian Somers memcpy(&dstipaddr.s_addr, cp + 6, 4); 112370ee81ffSBrian Somers snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 1124dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 1125af57ed9fSAtsushi Murai 11269780ef31SBrian Somers switch (mode_type) { 1127af57ed9fSAtsushi Murai case MODE_REQ: 11285d9e6103SBrian Somers memcpy(dec->rejend, cp, length); 11295d9e6103SBrian Somers dec->rejend += length; 1130af57ed9fSAtsushi Murai break; 11318fa6ebe4SBrian Somers 1132af57ed9fSAtsushi Murai case MODE_NAK: 1133af57ed9fSAtsushi Murai case MODE_REJ: 1134af57ed9fSAtsushi Murai break; 1135af57ed9fSAtsushi Murai } 1136af57ed9fSAtsushi Murai break; 1137d8e55738SJordan K. Hubbard 11383edeb0c6SBrian Somers case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ 1139d8e55738SJordan K. Hubbard case TY_SECONDARY_DNS: 11409e8ec64bSBrian Somers memcpy(&ipaddr.s_addr, cp + 2, 4); 1141dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 11423edeb0c6SBrian Somers 11439780ef31SBrian Somers switch (mode_type) { 1144d8e55738SJordan K. Hubbard case MODE_REQ: 11453edeb0c6SBrian Somers if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { 11463edeb0c6SBrian Somers ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 114730c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 114830c2f2ffSBrian Somers dec->rejend += length; 1149d8e55738SJordan K. Hubbard break; 1150d8e55738SJordan K. Hubbard } 11513edeb0c6SBrian Somers if (!gotdns) { 11523edeb0c6SBrian Somers dns[0] = ipcp->cfg.ns.dns[0]; 11533edeb0c6SBrian Somers dns[1] = ipcp->cfg.ns.dns[1]; 11543edeb0c6SBrian Somers if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) 11553edeb0c6SBrian Somers getdns(ipcp, dns); 11563edeb0c6SBrian Somers gotdns = 1; 11573edeb0c6SBrian Somers } 11583edeb0c6SBrian Somers have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; 1159944f7098SBrian Somers 11603edeb0c6SBrian Somers if (ipaddr.s_addr != have_ip.s_addr) { 11611ae349f5Scvs2svn /* 11623edeb0c6SBrian Somers * The client has got the DNS stuff wrong (first request) so 11631ae349f5Scvs2svn * we'll tell 'em how it is 11641ae349f5Scvs2svn */ 116530c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ 11663edeb0c6SBrian Somers memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); 116730c2f2ffSBrian Somers dec->nakend += length; 11683edeb0c6SBrian Somers } else { 1169d8e55738SJordan K. Hubbard /* 1170944f7098SBrian Somers * Otherwise they have it right (this time) so we send a ack packet 1171944f7098SBrian Somers * back confirming it... end of story 1172d8e55738SJordan K. Hubbard */ 117330c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 117430c2f2ffSBrian Somers dec->ackend += length; 11753edeb0c6SBrian Somers } 1176d8e55738SJordan K. Hubbard break; 11778fa6ebe4SBrian Somers 1178d8e55738SJordan K. Hubbard case MODE_NAK: /* what does this mean?? */ 11793edeb0c6SBrian Somers if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 11803edeb0c6SBrian Somers gotdnsnak = 1; 11819e8ec64bSBrian Somers memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4); 11823edeb0c6SBrian Somers } 1183d8e55738SJordan K. Hubbard break; 11848fa6ebe4SBrian Somers 11853edeb0c6SBrian Somers case MODE_REJ: /* Can't do much, stop asking */ 11863edeb0c6SBrian Somers ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); 1187d8e55738SJordan K. Hubbard break; 1188d8e55738SJordan K. Hubbard } 1189d8e55738SJordan K. Hubbard break; 1190d8e55738SJordan K. Hubbard 11913edeb0c6SBrian Somers case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ 1192d8e55738SJordan K. Hubbard case TY_SECONDARY_NBNS: 11939e8ec64bSBrian Somers memcpy(&ipaddr.s_addr, cp + 2, 4); 1194dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 11953edeb0c6SBrian Somers 11969780ef31SBrian Somers switch (mode_type) { 1197d8e55738SJordan K. Hubbard case MODE_REQ: 11983edeb0c6SBrian Somers have_ip.s_addr = 11993edeb0c6SBrian Somers ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; 12003edeb0c6SBrian Somers 12013edeb0c6SBrian Somers if (have_ip.s_addr == INADDR_ANY) { 1202dd7e2610SBrian Somers log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); 12033edeb0c6SBrian Somers ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 120430c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 120530c2f2ffSBrian Somers dec->rejend += length; 1206d8e55738SJordan K. Hubbard break; 1207d8e55738SJordan K. Hubbard } 12083edeb0c6SBrian Somers 12093edeb0c6SBrian Somers if (ipaddr.s_addr != have_ip.s_addr) { 121030c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 12113edeb0c6SBrian Somers memcpy(dec->nakend+2, &have_ip.s_addr, length); 121230c2f2ffSBrian Somers dec->nakend += length; 12133edeb0c6SBrian Somers } else { 121430c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 121530c2f2ffSBrian Somers dec->ackend += length; 12163edeb0c6SBrian Somers } 1217d8e55738SJordan K. Hubbard break; 12188fa6ebe4SBrian Somers 1219d8e55738SJordan K. Hubbard case MODE_NAK: 1220dd7e2610SBrian Somers log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 1221d8e55738SJordan K. Hubbard break; 12228fa6ebe4SBrian Somers 1223d8e55738SJordan K. Hubbard case MODE_REJ: 1224dd7e2610SBrian Somers log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 1225d8e55738SJordan K. Hubbard break; 1226d8e55738SJordan K. Hubbard } 1227d8e55738SJordan K. Hubbard break; 1228d8e55738SJordan K. Hubbard 1229af57ed9fSAtsushi Murai default: 123030c2f2ffSBrian Somers if (mode_type != MODE_NOP) { 123183d1af55SBrian Somers ipcp->my_reject |= (1 << type); 123230c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 123330c2f2ffSBrian Somers dec->rejend += length; 123430c2f2ffSBrian Somers } 1235af57ed9fSAtsushi Murai break; 1236af57ed9fSAtsushi Murai } 1237af57ed9fSAtsushi Murai plen -= length; 1238af57ed9fSAtsushi Murai cp += length; 1239af57ed9fSAtsushi Murai } 12401342caedSBrian Somers 12413edeb0c6SBrian Somers if (gotdnsnak) 12423edeb0c6SBrian Somers if (!setdns(ipcp, dnsnak)) { 12433edeb0c6SBrian Somers ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); 12443edeb0c6SBrian Somers ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); 12453edeb0c6SBrian Somers } 12463edeb0c6SBrian Somers 1247e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 12481342caedSBrian Somers if (dec->rejend != dec->rej) { 12491342caedSBrian Somers /* rejects are preferred */ 12501342caedSBrian Somers dec->ackend = dec->ack; 12511342caedSBrian Somers dec->nakend = dec->nak; 12521342caedSBrian Somers } else if (dec->nakend != dec->nak) 12531342caedSBrian Somers /* then NAKs */ 12541342caedSBrian Somers dec->ackend = dec->ack; 12551ae349f5Scvs2svn } 1256af57ed9fSAtsushi Murai } 1257af57ed9fSAtsushi Murai 12585d9e6103SBrian Somers extern struct mbuf * 12595d9e6103SBrian Somers ipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 1260af57ed9fSAtsushi Murai { 12617308ec68SBrian Somers /* Got PROTO_IPCP from link */ 1262411675baSBrian Somers mbuf_SetType(bp, MB_IPCPIN); 1263641684cdSBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 12645d9e6103SBrian Somers fsm_Input(&bundle->ncp.ipcp.fsm, bp); 1265641684cdSBrian Somers else { 1266641684cdSBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK) 1267641684cdSBrian Somers log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", 12685d9e6103SBrian Somers l->name, bundle_PhaseName(bundle)); 1269641684cdSBrian Somers mbuf_Free(bp); 1270641684cdSBrian Somers } 12715d9e6103SBrian Somers return NULL; 1272af57ed9fSAtsushi Murai } 12739c97abd8SBrian Somers 12749c97abd8SBrian Somers int 1275972a1bcfSBrian Somers ipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr) 1276972a1bcfSBrian Somers { 1277972a1bcfSBrian Somers struct ipcp *ipcp = &bundle->ncp.ipcp; 1278972a1bcfSBrian Somers 1279972a1bcfSBrian Somers memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 1280972a1bcfSBrian Somers iplist_reset(&ipcp->cfg.peer_list); 1281972a1bcfSBrian Somers ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr; 1282972a1bcfSBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 1283972a1bcfSBrian Somers ipcp->cfg.peer_range.width = 32; 1284972a1bcfSBrian Somers 1285972a1bcfSBrian Somers if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0) 1286972a1bcfSBrian Somers return 0; 1287972a1bcfSBrian Somers 1288972a1bcfSBrian Somers return 1; /* Ok */ 1289972a1bcfSBrian Somers } 1290972a1bcfSBrian Somers 1291972a1bcfSBrian Somers int 1292dd7e2610SBrian Somers ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 12939c97abd8SBrian Somers { 12945828db6dSBrian Somers struct ipcp *ipcp = &bundle->ncp.ipcp; 12955828db6dSBrian Somers 12967308ec68SBrian Somers /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 12975828db6dSBrian Somers memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 12985828db6dSBrian Somers iplist_reset(&ipcp->cfg.peer_list); 12999c97abd8SBrian Somers if (strpbrk(hisaddr, ",-")) { 13005828db6dSBrian Somers iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); 13015828db6dSBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 13025828db6dSBrian Somers iplist_setrandpos(&ipcp->cfg.peer_list); 130330c2f2ffSBrian Somers ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); 13045828db6dSBrian Somers if (ipcp->peer_ip.s_addr == INADDR_ANY) { 1305dd7e2610SBrian Somers log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); 13061d1fc017SBrian Somers return 0; 13079c97abd8SBrian Somers } 13085828db6dSBrian Somers ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; 13095828db6dSBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 13105828db6dSBrian Somers ipcp->cfg.peer_range.width = 32; 13119c97abd8SBrian Somers } else { 1312dd7e2610SBrian Somers log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); 13139c97abd8SBrian Somers return 0; 13149c97abd8SBrian Somers } 1315972a1bcfSBrian Somers } else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr, 13165828db6dSBrian Somers &ipcp->cfg.peer_range.mask, 13175828db6dSBrian Somers &ipcp->cfg.peer_range.width) != 0) { 13185828db6dSBrian Somers ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; 13199c97abd8SBrian Somers 132030c2f2ffSBrian Somers if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, 13218fa6ebe4SBrian Somers ipcp->cfg.peer_range.ipaddr, 0) < 0) 13229c97abd8SBrian Somers return 0; 13239c97abd8SBrian Somers } else 13249c97abd8SBrian Somers return 0; 13259c97abd8SBrian Somers 13261d1fc017SBrian Somers bundle_AdjustFilters(bundle, NULL, &ipcp->peer_ip); 13271d1fc017SBrian Somers 13281d1fc017SBrian Somers return 1; /* Ok */ 13299c97abd8SBrian Somers } 1330bc76350eSBrian Somers 1331bc76350eSBrian Somers struct in_addr 1332bc76350eSBrian Somers addr2mask(struct in_addr addr) 1333bc76350eSBrian Somers { 1334bc76350eSBrian Somers u_int32_t haddr = ntohl(addr.s_addr); 1335bc76350eSBrian Somers 1336bc76350eSBrian Somers haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET : 1337bc76350eSBrian Somers IN_CLASSB(haddr) ? IN_CLASSB_NET : 1338bc76350eSBrian Somers IN_CLASSC_NET; 1339bc76350eSBrian Somers addr.s_addr = htonl(haddr); 1340bc76350eSBrian Somers 1341bc76350eSBrian Somers return addr; 1342bc76350eSBrian Somers } 1343