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 92da477886SBrian Somers static u_short default_urgent_tcp_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 102da477886SBrian Somers static u_short default_urgent_udp_ports[] = { }; 103da477886SBrian Somers 104da477886SBrian Somers #define NDEFTCPPORTS \ 105da477886SBrian Somers (sizeof default_urgent_tcp_ports / sizeof default_urgent_tcp_ports[0]) 106da477886SBrian Somers #define NDEFUDPPORTS \ 107da477886SBrian Somers (sizeof default_urgent_udp_ports / sizeof default_urgent_udp_ports[0]) 108442f8495SBrian Somers 109442f8495SBrian Somers int 110da477886SBrian Somers ipcp_IsUrgentPort(struct port_range *range, u_short src, u_short dst) 111442f8495SBrian Somers { 112442f8495SBrian Somers int f; 113442f8495SBrian Somers 114da477886SBrian Somers for (f = 0; f < range->nports; f++) 115da477886SBrian Somers if (range->port[f] == src || range->port[f] == dst) 116442f8495SBrian Somers return 1; 117442f8495SBrian Somers 118442f8495SBrian Somers return 0; 119442f8495SBrian Somers } 120442f8495SBrian Somers 121442f8495SBrian Somers void 122da477886SBrian Somers ipcp_AddUrgentPort(struct port_range *range, u_short port) 123442f8495SBrian Somers { 124442f8495SBrian Somers u_short *newport; 125442f8495SBrian Somers int p; 126442f8495SBrian Somers 127da477886SBrian Somers if (range->nports == range->maxports) { 128da477886SBrian Somers range->maxports += 10; 129da477886SBrian Somers newport = (u_short *)realloc(range->port, 130da477886SBrian Somers range->maxports * sizeof(u_short)); 131442f8495SBrian Somers if (newport == NULL) { 132442f8495SBrian Somers log_Printf(LogERROR, "ipcp_AddUrgentPort: realloc: %s\n", 133442f8495SBrian Somers strerror(errno)); 134da477886SBrian Somers range->maxports -= 10; 135442f8495SBrian Somers return; 136442f8495SBrian Somers } 137da477886SBrian Somers range->port = newport; 138442f8495SBrian Somers } 139442f8495SBrian Somers 140da477886SBrian Somers for (p = 0; p < range->nports; p++) 141da477886SBrian Somers if (range->port[p] == port) { 142442f8495SBrian Somers log_Printf(LogWARN, "%u: Port already set to urgent\n", port); 143442f8495SBrian Somers break; 144da477886SBrian Somers } else if (range->port[p] > port) { 145da477886SBrian Somers memmove(range->port + p + 1, range->port + p, 146da477886SBrian Somers (range->nports - p) * sizeof(u_short)); 147da477886SBrian Somers range->port[p] = port; 148da477886SBrian Somers range->nports++; 149442f8495SBrian Somers break; 150442f8495SBrian Somers } 151442f8495SBrian Somers 152da477886SBrian Somers if (p == range->nports) 153da477886SBrian Somers range->port[range->nports++] = port; 154442f8495SBrian Somers } 155442f8495SBrian Somers 156442f8495SBrian Somers void 157da477886SBrian Somers ipcp_RemoveUrgentPort(struct port_range *range, u_short port) 158442f8495SBrian Somers { 159442f8495SBrian Somers int p; 160442f8495SBrian Somers 161da477886SBrian Somers for (p = 0; p < range->nports; p++) 162da477886SBrian Somers if (range->port[p] == port) { 163da477886SBrian Somers if (p != range->nports - 1) 164da477886SBrian Somers memmove(range->port + p, range->port + p + 1, 165da477886SBrian Somers (range->nports - p - 1) * sizeof(u_short)); 166da477886SBrian Somers range->nports--; 167442f8495SBrian Somers return; 168442f8495SBrian Somers } 169442f8495SBrian Somers 170da477886SBrian Somers if (p == range->nports) 171442f8495SBrian Somers log_Printf(LogWARN, "%u: Port not set to urgent\n", port); 172442f8495SBrian Somers } 173442f8495SBrian Somers 174442f8495SBrian Somers void 175da477886SBrian Somers ipcp_ClearUrgentPorts(struct port_range *range) 176442f8495SBrian Somers { 177da477886SBrian Somers range->nports = 0; 178442f8495SBrian Somers } 179442f8495SBrian Somers 18029e275ceSBrian Somers struct compreq { 18129e275ceSBrian Somers u_short proto; 18229e275ceSBrian Somers u_char slots; 18329e275ceSBrian Somers u_char compcid; 18429e275ceSBrian Somers }; 18575240ed1SBrian Somers 1866f384573SBrian Somers static int IpcpLayerUp(struct fsm *); 1871ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *); 188927145beSBrian Somers static void IpcpLayerStart(struct fsm *); 189927145beSBrian Somers static void IpcpLayerFinish(struct fsm *); 190479508cfSBrian Somers static void IpcpInitRestartCounter(struct fsm *, int); 1917308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *); 1922267893fSBrian Somers static void IpcpSentTerminateReq(struct fsm *); 1932267893fSBrian Somers static void IpcpSendTerminateAck(struct fsm *, u_char); 19430c2f2ffSBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int, 19530c2f2ffSBrian Somers struct fsm_decode *); 196af57ed9fSAtsushi Murai 19783d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = { 198af57ed9fSAtsushi Murai IpcpLayerUp, 199af57ed9fSAtsushi Murai IpcpLayerDown, 200af57ed9fSAtsushi Murai IpcpLayerStart, 201af57ed9fSAtsushi Murai IpcpLayerFinish, 202af57ed9fSAtsushi Murai IpcpInitRestartCounter, 203af57ed9fSAtsushi Murai IpcpSendConfigReq, 2042267893fSBrian Somers IpcpSentTerminateReq, 205af57ed9fSAtsushi Murai IpcpSendTerminateAck, 206af57ed9fSAtsushi Murai IpcpDecodeConfig, 207dd7e2610SBrian Somers fsm_NullRecvResetReq, 208dd7e2610SBrian Somers fsm_NullRecvResetAck 209af57ed9fSAtsushi Murai }; 210af57ed9fSAtsushi Murai 211b6e82f33SBrian Somers static const char *cftypes[] = { 2129e836af5SBrian Somers /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 2139e836af5SBrian Somers "???", 2149e836af5SBrian Somers "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ 2159e836af5SBrian Somers "COMPPROTO", /* 2: IP-Compression-Protocol */ 2169e836af5SBrian Somers "IPADDR", /* 3: IP-Address */ 217af57ed9fSAtsushi Murai }; 218af57ed9fSAtsushi Murai 21970ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 2209e836af5SBrian Somers 221b6e82f33SBrian Somers static const char *cftypes128[] = { 2229e836af5SBrian Somers /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 2239e836af5SBrian Somers "???", 2249e836af5SBrian Somers "PRIDNS", /* 129: Primary DNS Server Address */ 2259e836af5SBrian Somers "PRINBNS", /* 130: Primary NBNS Server Address */ 2269e836af5SBrian Somers "SECDNS", /* 131: Secondary DNS Server Address */ 2279e836af5SBrian Somers "SECNBNS", /* 132: Secondary NBNS Server Address */ 2289e836af5SBrian Somers }; 2299e836af5SBrian Somers 23070ee81ffSBrian Somers #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) 2319e836af5SBrian Somers 2329a0b991fSBrian Somers void 2335828db6dSBrian Somers ipcp_AddInOctets(struct ipcp *ipcp, int n) 234af57ed9fSAtsushi Murai { 2355828db6dSBrian Somers throughput_addin(&ipcp->throughput, n); 236af57ed9fSAtsushi Murai } 237af57ed9fSAtsushi Murai 2389a0b991fSBrian Somers void 2395828db6dSBrian Somers ipcp_AddOutOctets(struct ipcp *ipcp, int n) 240af57ed9fSAtsushi Murai { 2415828db6dSBrian Somers throughput_addout(&ipcp->throughput, n); 2421ae349f5Scvs2svn } 2431ae349f5Scvs2svn 2443edeb0c6SBrian Somers static void 2453edeb0c6SBrian Somers getdns(struct ipcp *ipcp, struct in_addr addr[2]) 2463edeb0c6SBrian Somers { 2473edeb0c6SBrian Somers FILE *fp; 2483edeb0c6SBrian Somers 2493edeb0c6SBrian Somers addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 2503edeb0c6SBrian Somers if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 2513edeb0c6SBrian Somers char buf[LINE_LEN], *cp, *end; 2523edeb0c6SBrian Somers int n; 2533edeb0c6SBrian Somers 2543edeb0c6SBrian Somers n = 0; 2553edeb0c6SBrian Somers buf[sizeof buf - 1] = '\0'; 2563edeb0c6SBrian Somers while (fgets(buf, sizeof buf - 1, fp)) { 2573edeb0c6SBrian Somers if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) { 2583edeb0c6SBrian Somers for (cp = buf + 11; issep(*cp); cp++) 2593edeb0c6SBrian Somers ; 2603edeb0c6SBrian Somers for (end = cp; isip(*end); end++) 2613edeb0c6SBrian Somers ; 2623edeb0c6SBrian Somers *end = '\0'; 2633edeb0c6SBrian Somers if (inet_aton(cp, addr+n) && ++n == 2) 2643edeb0c6SBrian Somers break; 2653edeb0c6SBrian Somers } 2663edeb0c6SBrian Somers } 2673edeb0c6SBrian Somers if (n == 1) 2683edeb0c6SBrian Somers addr[1] = addr[0]; 2693edeb0c6SBrian Somers fclose(fp); 2703edeb0c6SBrian Somers } 2713edeb0c6SBrian Somers } 2723edeb0c6SBrian Somers 2733edeb0c6SBrian Somers static int 2743edeb0c6SBrian Somers setdns(struct ipcp *ipcp, struct in_addr addr[2]) 2753edeb0c6SBrian Somers { 2763edeb0c6SBrian Somers FILE *fp; 2773edeb0c6SBrian Somers char wbuf[LINE_LEN + 54]; 2783edeb0c6SBrian Somers int wlen; 2793edeb0c6SBrian Somers 2803edeb0c6SBrian Somers if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) { 2813edeb0c6SBrian Somers struct in_addr old[2]; 2823edeb0c6SBrian Somers 2833edeb0c6SBrian Somers getdns(ipcp, old); 2843edeb0c6SBrian Somers if (addr[0].s_addr == INADDR_ANY) 2853edeb0c6SBrian Somers addr[0] = old[0]; 2863edeb0c6SBrian Somers if (addr[1].s_addr == INADDR_ANY) 2873edeb0c6SBrian Somers addr[1] = old[1]; 2883edeb0c6SBrian Somers } 2893edeb0c6SBrian Somers 2903edeb0c6SBrian Somers if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) { 291dd7e2610SBrian Somers log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n", 2923edeb0c6SBrian Somers _PATH_RESCONF); 2933edeb0c6SBrian Somers return 0; 2943edeb0c6SBrian Somers } 2953edeb0c6SBrian Somers 2963edeb0c6SBrian Somers wlen = 0; 2973edeb0c6SBrian Somers if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 2983edeb0c6SBrian Somers char buf[LINE_LEN]; 2993edeb0c6SBrian Somers int len; 3003edeb0c6SBrian Somers 3013edeb0c6SBrian Somers buf[sizeof buf - 1] = '\0'; 3023edeb0c6SBrian Somers while (fgets(buf, sizeof buf - 1, fp)) { 3033edeb0c6SBrian Somers if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) { 3043edeb0c6SBrian Somers len = strlen(buf); 3053edeb0c6SBrian Somers if (len > sizeof wbuf - wlen) { 306dd7e2610SBrian Somers log_Printf(LogWARN, "%s: Can only cope with max file size %d\n", 3073edeb0c6SBrian Somers _PATH_RESCONF, LINE_LEN); 3083edeb0c6SBrian Somers fclose(fp); 3093edeb0c6SBrian Somers return 0; 3103edeb0c6SBrian Somers } 3113edeb0c6SBrian Somers memcpy(wbuf + wlen, buf, len); 3123edeb0c6SBrian Somers wlen += len; 3133edeb0c6SBrian Somers } 3143edeb0c6SBrian Somers } 3153edeb0c6SBrian Somers fclose(fp); 3163edeb0c6SBrian Somers } 3173edeb0c6SBrian Somers 3183edeb0c6SBrian Somers if (addr[0].s_addr != INADDR_ANY) { 3193edeb0c6SBrian Somers snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 3203edeb0c6SBrian Somers inet_ntoa(addr[0])); 321dd7e2610SBrian Somers log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11); 3223edeb0c6SBrian Somers wlen += strlen(wbuf + wlen); 3233edeb0c6SBrian Somers } 3243edeb0c6SBrian Somers 3253edeb0c6SBrian Somers if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) { 3263edeb0c6SBrian Somers snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 3273edeb0c6SBrian Somers inet_ntoa(addr[1])); 328dd7e2610SBrian Somers log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11); 3293edeb0c6SBrian Somers wlen += strlen(wbuf + wlen); 3303edeb0c6SBrian Somers } 3313edeb0c6SBrian Somers 3323edeb0c6SBrian Somers if (wlen) { 3333edeb0c6SBrian Somers int fd; 3343edeb0c6SBrian Somers 3353edeb0c6SBrian Somers if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) { 3363edeb0c6SBrian Somers if (write(fd, wbuf, wlen) != wlen) { 337dd7e2610SBrian Somers log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno)); 3383edeb0c6SBrian Somers close(fd); 3393edeb0c6SBrian Somers return 0; 3403edeb0c6SBrian Somers } 3413edeb0c6SBrian Somers if (ftruncate(fd, wlen) == -1) { 342dd7e2610SBrian Somers log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno)); 3433edeb0c6SBrian Somers close(fd); 3443edeb0c6SBrian Somers return 0; 3453edeb0c6SBrian Somers } 3463edeb0c6SBrian Somers close(fd); 3473edeb0c6SBrian Somers } else { 348dd7e2610SBrian Somers log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno)); 3493edeb0c6SBrian Somers return 0; 3503edeb0c6SBrian Somers } 3513edeb0c6SBrian Somers } 3523edeb0c6SBrian Somers 3533edeb0c6SBrian Somers return 1; 354af57ed9fSAtsushi Murai } 355af57ed9fSAtsushi Murai 356274e766cSBrian Somers int 357dd7e2610SBrian Somers ipcp_Show(struct cmdargs const *arg) 358af57ed9fSAtsushi Murai { 359610b185fSBrian Somers struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 360442f8495SBrian Somers int p; 361af57ed9fSAtsushi Murai 362610b185fSBrian Somers prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, 363610b185fSBrian Somers State2Nam(ipcp->fsm.state)); 364610b185fSBrian Somers if (ipcp->fsm.state == ST_OPENED) { 365b6217683SBrian Somers prompt_Printf(arg->prompt, " His side: %s, %s\n", 366610b185fSBrian Somers inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); 367b6217683SBrian Somers prompt_Printf(arg->prompt, " My side: %s, %s\n", 368610b185fSBrian Somers inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); 369442f8495SBrian Somers prompt_Printf(arg->prompt, " Queued packets: %d\n", ip_QueueLen(ipcp)); 370d1a3ea47SBrian Somers } 3715b4c5b00SBrian Somers 372610b185fSBrian Somers if (ipcp->route) { 373610b185fSBrian Somers prompt_Printf(arg->prompt, "\n"); 374972a1bcfSBrian Somers route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1); 3751ae349f5Scvs2svn } 376927145beSBrian Somers 377b6217683SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 378479508cfSBrian Somers prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 379479508cfSBrian Somers " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout, 380479508cfSBrian Somers ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s", 381479508cfSBrian Somers ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s"); 38250abd4c8SBrian Somers prompt_Printf(arg->prompt, " My Address: %s/%d", 383610b185fSBrian Somers inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width); 384bc76350eSBrian Somers prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask)); 385610b185fSBrian Somers if (ipcp->cfg.HaveTriggerAddress) 386bc76350eSBrian Somers prompt_Printf(arg->prompt, " Trigger address: %s\n", 387610b185fSBrian Somers inet_ntoa(ipcp->cfg.TriggerAddress)); 388bc76350eSBrian Somers 389bc76350eSBrian Somers prompt_Printf(arg->prompt, " VJ compression: %s (%d slots %s slot " 390610b185fSBrian Somers "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), 391610b185fSBrian Somers ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); 39250abd4c8SBrian Somers 393610b185fSBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) 394b6217683SBrian Somers prompt_Printf(arg->prompt, " His Address: %s\n", 395610b185fSBrian Somers ipcp->cfg.peer_list.src); 3961ae349f5Scvs2svn else 397b6217683SBrian Somers prompt_Printf(arg->prompt, " His Address: %s/%d\n", 398610b185fSBrian Somers inet_ntoa(ipcp->cfg.peer_range.ipaddr), 399610b185fSBrian Somers ipcp->cfg.peer_range.width); 40050abd4c8SBrian Somers 4013edeb0c6SBrian Somers prompt_Printf(arg->prompt, " DNS: %s, ", 402610b185fSBrian Somers inet_ntoa(ipcp->cfg.ns.dns[0])); 403610b185fSBrian Somers prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]), 404610b185fSBrian Somers command_ShowNegval(ipcp->cfg.ns.dns_neg)); 4053edeb0c6SBrian Somers prompt_Printf(arg->prompt, " NetBIOS NS: %s, ", 406610b185fSBrian Somers inet_ntoa(ipcp->cfg.ns.nbns[0])); 407610b185fSBrian Somers prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1])); 4081342caedSBrian Somers 409da477886SBrian Somers prompt_Printf(arg->prompt, " Urgent ports\n"); 410da477886SBrian Somers prompt_Printf(arg->prompt, " TCP: "); 411da477886SBrian Somers if (ipcp->cfg.urgent.tcp.nports == 0) 412442f8495SBrian Somers prompt_Printf(arg->prompt, "none"); 413442f8495SBrian Somers else 414da477886SBrian Somers for (p = 0; p < ipcp->cfg.urgent.tcp.nports; p++) { 415442f8495SBrian Somers if (p) 416442f8495SBrian Somers prompt_Printf(arg->prompt, ", "); 417da477886SBrian Somers prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.tcp.port[p]); 418da477886SBrian Somers } 419da477886SBrian Somers prompt_Printf(arg->prompt, "\n UDP: "); 420da477886SBrian Somers if (ipcp->cfg.urgent.udp.nports == 0) 421da477886SBrian Somers prompt_Printf(arg->prompt, "none"); 422da477886SBrian Somers else 423da477886SBrian Somers for (p = 0; p < ipcp->cfg.urgent.udp.nports; p++) { 424da477886SBrian Somers if (p) 425da477886SBrian Somers prompt_Printf(arg->prompt, ", "); 426da477886SBrian Somers prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.udp.port[p]); 427442f8495SBrian Somers } 428442f8495SBrian Somers 429442f8495SBrian Somers prompt_Printf(arg->prompt, "\n\n"); 430610b185fSBrian Somers throughput_disp(&ipcp->throughput, arg->prompt); 4319a0b991fSBrian Somers 432927145beSBrian Somers return 0; 433af57ed9fSAtsushi Murai } 434af57ed9fSAtsushi Murai 435d1a3ea47SBrian Somers int 436dd7e2610SBrian Somers ipcp_vjset(struct cmdargs const *arg) 437d1a3ea47SBrian Somers { 43825092092SBrian Somers if (arg->argc != arg->argn+2) 439d1a3ea47SBrian Somers return -1; 44025092092SBrian Somers if (!strcasecmp(arg->argv[arg->argn], "slots")) { 441d1a3ea47SBrian Somers int slots; 442d1a3ea47SBrian Somers 44325092092SBrian Somers slots = atoi(arg->argv[arg->argn+1]); 444d1a3ea47SBrian Somers if (slots < 4 || slots > 16) 445d1a3ea47SBrian Somers return 1; 4461342caedSBrian Somers arg->bundle->ncp.ipcp.cfg.vj.slots = slots; 447d1a3ea47SBrian Somers return 0; 44825092092SBrian Somers } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { 44925092092SBrian Somers if (!strcasecmp(arg->argv[arg->argn+1], "on")) 4501342caedSBrian Somers arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; 45125092092SBrian Somers else if (!strcasecmp(arg->argv[arg->argn+1], "off")) 4521342caedSBrian Somers arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; 453d1a3ea47SBrian Somers else 454d1a3ea47SBrian Somers return 2; 455d1a3ea47SBrian Somers return 0; 456d1a3ea47SBrian Somers } 457d1a3ea47SBrian Somers return -1; 458d1a3ea47SBrian Somers } 459d1a3ea47SBrian Somers 4601ae349f5Scvs2svn void 4616d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, 4626d666775SBrian Somers const struct fsm_parent *parent) 463d1a3ea47SBrian Somers { 464503a7782SBrian Somers struct hostent *hp; 465503a7782SBrian Somers char name[MAXHOSTNAMELEN]; 4663b0f8d2eSBrian Somers static const char *timer_names[] = 4673b0f8d2eSBrian Somers {"IPCP restart", "IPCP openmode", "IPCP stopped"}; 46829e275ceSBrian Somers 469479508cfSBrian Somers fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP, 4703b0f8d2eSBrian Somers bundle, l, parent, &ipcp_Callbacks, timer_names); 471503a7782SBrian Somers 472610b185fSBrian Somers ipcp->route = NULL; 4731342caedSBrian Somers ipcp->cfg.vj.slots = DEF_VJ_STATES; 4741342caedSBrian Somers ipcp->cfg.vj.slotcomp = 1; 475503a7782SBrian Somers memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 476503a7782SBrian Somers if (gethostname(name, sizeof name) == 0) { 477503a7782SBrian Somers hp = gethostbyname(name); 4788fa6ebe4SBrian Somers if (hp && hp->h_addrtype == AF_INET) 479503a7782SBrian Somers memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); 480503a7782SBrian Somers } 48130c2f2ffSBrian Somers ipcp->cfg.netmask.s_addr = INADDR_ANY; 482503a7782SBrian Somers memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 483503a7782SBrian Somers iplist_setsrc(&ipcp->cfg.peer_list, ""); 484503a7782SBrian Somers ipcp->cfg.HaveTriggerAddress = 0; 485503a7782SBrian Somers 4863edeb0c6SBrian Somers ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY; 4873edeb0c6SBrian Somers ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY; 4883edeb0c6SBrian Somers ipcp->cfg.ns.dns_neg = 0; 4893edeb0c6SBrian Somers ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; 4903edeb0c6SBrian Somers ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; 491cd9647a1SBrian Somers 492da477886SBrian Somers ipcp->cfg.urgent.tcp.nports = ipcp->cfg.urgent.tcp.maxports = NDEFTCPPORTS; 493da477886SBrian Somers ipcp->cfg.urgent.tcp.port = (u_short *)malloc(NDEFTCPPORTS * sizeof(u_short)); 494da477886SBrian Somers memcpy(ipcp->cfg.urgent.tcp.port, default_urgent_tcp_ports, 495da477886SBrian Somers NDEFTCPPORTS * sizeof(u_short)); 496da477886SBrian Somers 497da477886SBrian Somers ipcp->cfg.urgent.udp.nports = ipcp->cfg.urgent.udp.maxports = NDEFUDPPORTS; 498da477886SBrian Somers ipcp->cfg.urgent.udp.port = (u_short *)malloc(NDEFUDPPORTS * sizeof(u_short)); 499da477886SBrian Somers memcpy(ipcp->cfg.urgent.udp.port, default_urgent_udp_ports, 500da477886SBrian Somers NDEFUDPPORTS * sizeof(u_short)); 501442f8495SBrian Somers 502479508cfSBrian Somers ipcp->cfg.fsm.timeout = DEF_FSMRETRY; 503479508cfSBrian Somers ipcp->cfg.fsm.maxreq = DEF_FSMTRIES; 504479508cfSBrian Somers ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES; 5051342caedSBrian Somers ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; 506503a7782SBrian Somers 507eaa4df37SBrian Somers memset(&ipcp->vj, '\0', sizeof ipcp->vj); 508eaa4df37SBrian Somers 509ab2de065SBrian Somers throughput_init(&ipcp->throughput, SAMPLE_PERIOD); 5105a72b6edSBrian Somers memset(ipcp->Queue, '\0', sizeof ipcp->Queue); 511972a1bcfSBrian Somers ipcp_Setup(ipcp, INADDR_NONE); 512d1a3ea47SBrian Somers } 513d1a3ea47SBrian Somers 514af57ed9fSAtsushi Murai void 515442f8495SBrian Somers ipcp_Destroy(struct ipcp *ipcp) 516442f8495SBrian Somers { 517da477886SBrian Somers if (ipcp->cfg.urgent.tcp.maxports) { 518da477886SBrian Somers ipcp->cfg.urgent.tcp.nports = ipcp->cfg.urgent.tcp.maxports = 0; 519da477886SBrian Somers free(ipcp->cfg.urgent.tcp.port); 520da477886SBrian Somers ipcp->cfg.urgent.tcp.port = NULL; 521da477886SBrian Somers } 522da477886SBrian Somers if (ipcp->cfg.urgent.udp.maxports) { 523da477886SBrian Somers ipcp->cfg.urgent.udp.nports = ipcp->cfg.urgent.udp.maxports = 0; 524da477886SBrian Somers free(ipcp->cfg.urgent.udp.port); 525da477886SBrian Somers ipcp->cfg.urgent.udp.port = NULL; 526442f8495SBrian Somers } 527442f8495SBrian Somers } 528442f8495SBrian Somers 529442f8495SBrian Somers void 530ce828a6eSBrian Somers ipcp_SetLink(struct ipcp *ipcp, struct link *l) 531af57ed9fSAtsushi Murai { 532ce828a6eSBrian Somers ipcp->fsm.link = l; 533af57ed9fSAtsushi Murai } 534549d663dSAtsushi Murai 535ce828a6eSBrian Somers void 536972a1bcfSBrian Somers ipcp_Setup(struct ipcp *ipcp, u_int32_t mask) 537503a7782SBrian Somers { 5388fa6ebe4SBrian Somers struct iface *iface = ipcp->fsm.bundle->iface; 5398fa6ebe4SBrian Somers int pos, n; 540503a7782SBrian Somers 541503a7782SBrian Somers ipcp->fsm.open_mode = 0; 542972a1bcfSBrian Somers ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask; 543503a7782SBrian Somers 544503a7782SBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 5458fa6ebe4SBrian Somers /* Try to give the peer a previously configured IP address */ 5468fa6ebe4SBrian Somers for (n = 0; n < iface->in_addrs; n++) { 5478fa6ebe4SBrian Somers pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd); 5488fa6ebe4SBrian Somers if (pos != -1) { 5498fa6ebe4SBrian Somers ipcp->cfg.peer_range.ipaddr = 5508fa6ebe4SBrian Somers iplist_setcurpos(&ipcp->cfg.peer_list, pos); 5518fa6ebe4SBrian Somers break; 5528fa6ebe4SBrian Somers } 5538fa6ebe4SBrian Somers } 5548fa6ebe4SBrian Somers if (n == iface->in_addrs) 5558fa6ebe4SBrian Somers /* Ok, so none of 'em fit.... pick a random one */ 556503a7782SBrian Somers ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); 5578fa6ebe4SBrian Somers 558503a7782SBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 559503a7782SBrian Somers ipcp->cfg.peer_range.width = 32; 560503a7782SBrian Somers } 561503a7782SBrian Somers 562503a7782SBrian Somers ipcp->heis1172 = 0; 563503a7782SBrian Somers 564503a7782SBrian Somers ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; 565503a7782SBrian Somers ipcp->peer_compproto = 0; 5661ae349f5Scvs2svn 5678390b576SBrian Somers if (ipcp->cfg.HaveTriggerAddress) { 568549d663dSAtsushi Murai /* 5695b4c5b00SBrian Somers * Some implementations of PPP require that we send a 5705b4c5b00SBrian Somers * *special* value as our address, even though the rfc specifies 5715b4c5b00SBrian Somers * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 572549d663dSAtsushi Murai */ 573503a7782SBrian Somers ipcp->my_ip = ipcp->cfg.TriggerAddress; 574dd7e2610SBrian Somers log_Printf(LogIPCP, "Using trigger address %s\n", 575503a7782SBrian Somers inet_ntoa(ipcp->cfg.TriggerAddress)); 5768fa6ebe4SBrian Somers } else { 5778390b576SBrian Somers /* 5788fa6ebe4SBrian Somers * Otherwise, if we've used an IP number before and it's still within 5798fa6ebe4SBrian Somers * the network specified on the ``set ifaddr'' line, we really 5808fa6ebe4SBrian Somers * want to keep that IP number so that we can keep any existing 5818fa6ebe4SBrian Somers * connections that are bound to that IP (assuming we're not 5828fa6ebe4SBrian Somers * ``iface-alias''ing). 5838390b576SBrian Somers */ 5848fa6ebe4SBrian Somers for (n = 0; n < iface->in_addrs; n++) 5858fa6ebe4SBrian Somers if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) == 5868fa6ebe4SBrian Somers (ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) { 5878fa6ebe4SBrian Somers ipcp->my_ip = iface->in_addr[n].ifa; 5888fa6ebe4SBrian Somers break; 5898fa6ebe4SBrian Somers } 5908fa6ebe4SBrian Somers if (n == iface->in_addrs) 591503a7782SBrian Somers ipcp->my_ip = ipcp->cfg.my_range.ipaddr; 5928fa6ebe4SBrian Somers } 59329e275ceSBrian Somers 594972a1bcfSBrian Somers if (IsEnabled(ipcp->cfg.vj.neg) 595972a1bcfSBrian Somers #ifndef NORADIUS 596972a1bcfSBrian Somers || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj) 597972a1bcfSBrian Somers #endif 598972a1bcfSBrian Somers ) 599503a7782SBrian Somers ipcp->my_compproto = (PROTO_VJCOMP << 16) + 6001342caedSBrian Somers ((ipcp->cfg.vj.slots - 1) << 8) + 6011342caedSBrian Somers ipcp->cfg.vj.slotcomp; 6021ae349f5Scvs2svn else 603503a7782SBrian Somers ipcp->my_compproto = 0; 6041342caedSBrian Somers sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); 60529e275ceSBrian Somers 606503a7782SBrian Somers ipcp->peer_reject = 0; 607503a7782SBrian Somers ipcp->my_reject = 0; 6081ae349f5Scvs2svn } 6091ae349f5Scvs2svn 610455aabc3SBrian Somers static int 6113afe5ccbSBrian Somers ipcp_doproxyall(struct bundle *bundle, 6123afe5ccbSBrian Somers int (*proxyfun)(struct bundle *, struct in_addr, int), int s) 6133afe5ccbSBrian Somers { 6143afe5ccbSBrian Somers int n, ret; 6153afe5ccbSBrian Somers struct sticky_route *rp; 6163afe5ccbSBrian Somers struct in_addr addr; 6173afe5ccbSBrian Somers struct ipcp *ipcp; 6183afe5ccbSBrian Somers 6193afe5ccbSBrian Somers ipcp = &bundle->ncp.ipcp; 6203afe5ccbSBrian Somers for (rp = ipcp->route; rp != NULL; rp = rp->next) { 621bc76350eSBrian Somers if (rp->mask.s_addr == INADDR_BROADCAST) 6223afe5ccbSBrian Somers continue; 623bc76350eSBrian Somers n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1; 6243afe5ccbSBrian Somers if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) { 6253afe5ccbSBrian Somers addr = rp->dst; 6263afe5ccbSBrian Somers while (n--) { 6273afe5ccbSBrian Somers addr.s_addr = htonl(ntohl(addr.s_addr) + 1); 6283afe5ccbSBrian Somers log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr)); 6293afe5ccbSBrian Somers ret = (*proxyfun)(bundle, addr, s); 6303afe5ccbSBrian Somers if (!ret) 6313afe5ccbSBrian Somers return ret; 6323afe5ccbSBrian Somers } 6333afe5ccbSBrian Somers } 6343afe5ccbSBrian Somers } 6353afe5ccbSBrian Somers 6363afe5ccbSBrian Somers return 0; 6373afe5ccbSBrian Somers } 6383afe5ccbSBrian Somers 6393afe5ccbSBrian Somers static int 64030c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, 64130c2f2ffSBrian Somers struct in_addr hisaddr, int silent) 642455aabc3SBrian Somers { 64368645f39SBrian Somers struct in_addr mask, oaddr, none = { INADDR_ANY }; 644455aabc3SBrian Somers 645bc76350eSBrian Somers mask = addr2mask(myaddr); 646455aabc3SBrian Somers 647972a1bcfSBrian Somers if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY && 648bc76350eSBrian Somers (bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr) 649bc76350eSBrian Somers mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr; 650455aabc3SBrian Somers 6518fa6ebe4SBrian Somers oaddr.s_addr = bundle->iface->in_addrs ? 6528fa6ebe4SBrian Somers bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY; 6538fa6ebe4SBrian Somers if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr, 6548fa6ebe4SBrian Somers IFACE_ADD_FIRST|IFACE_FORCE_ADD)) 6558fa6ebe4SBrian Somers return -1; 656455aabc3SBrian Somers 6578fa6ebe4SBrian Somers if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1 6588fa6ebe4SBrian Somers && myaddr.s_addr != oaddr.s_addr) 6598fa6ebe4SBrian Somers /* Nuke the old one */ 6608fa6ebe4SBrian Somers iface_inDelete(bundle->iface, oaddr); 661455aabc3SBrian Somers 6623afe5ccbSBrian Somers if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0) 6633afe5ccbSBrian Somers bundle_SetRoute(bundle, RTM_CHANGE, hisaddr, myaddr, none, 0, 0); 6643afe5ccbSBrian Somers 665610b185fSBrian Somers if (Enabled(bundle, OPT_SROUTES)) 666610b185fSBrian Somers route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); 667610b185fSBrian Somers 668972a1bcfSBrian Somers #ifndef NORADIUS 669972a1bcfSBrian Somers if (bundle->radius.valid) 670972a1bcfSBrian Somers route_Change(bundle, bundle->radius.routes, myaddr, hisaddr); 671972a1bcfSBrian Somers #endif 672972a1bcfSBrian Somers 6733afe5ccbSBrian Somers if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) { 6748fa6ebe4SBrian Somers int s = ID0socket(AF_INET, SOCK_DGRAM, 0); 6758fa6ebe4SBrian Somers if (s < 0) 6768fa6ebe4SBrian Somers log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n", 6778fa6ebe4SBrian Somers strerror(errno)); 6788fa6ebe4SBrian Somers else { 6793afe5ccbSBrian Somers if (Enabled(bundle, OPT_PROXYALL)) 6803afe5ccbSBrian Somers ipcp_doproxyall(bundle, arp_SetProxy, s); 6813afe5ccbSBrian Somers else if (Enabled(bundle, OPT_PROXY)) 6828fa6ebe4SBrian Somers arp_SetProxy(bundle, hisaddr, s); 683455aabc3SBrian Somers close(s); 6848fa6ebe4SBrian Somers } 6858fa6ebe4SBrian Somers } 6868fa6ebe4SBrian Somers 6878fa6ebe4SBrian Somers return 0; 688455aabc3SBrian Somers } 689455aabc3SBrian Somers 690455aabc3SBrian Somers static struct in_addr 6918fa6ebe4SBrian Somers ChooseHisAddr(struct bundle *bundle, struct in_addr gw) 692455aabc3SBrian Somers { 693455aabc3SBrian Somers struct in_addr try; 6943a2e4f62SBrian Somers u_long f; 695455aabc3SBrian Somers 6965828db6dSBrian Somers for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { 6975828db6dSBrian Somers try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); 6983a2e4f62SBrian Somers log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n", 699455aabc3SBrian Somers f, inet_ntoa(try)); 70030c2f2ffSBrian Somers if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { 701dd7e2610SBrian Somers log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); 702455aabc3SBrian Somers break; 703455aabc3SBrian Somers } 704455aabc3SBrian Somers } 705455aabc3SBrian Somers 7065828db6dSBrian Somers if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { 707dd7e2610SBrian Somers log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 708455aabc3SBrian Somers try.s_addr = INADDR_ANY; 709455aabc3SBrian Somers } 710455aabc3SBrian Somers 711455aabc3SBrian Somers return try; 712af57ed9fSAtsushi Murai } 713af57ed9fSAtsushi Murai 714af57ed9fSAtsushi Murai static void 715479508cfSBrian Somers IpcpInitRestartCounter(struct fsm *fp, int what) 716af57ed9fSAtsushi Murai { 7177308ec68SBrian Somers /* Set fsm timer load */ 718cd9647a1SBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 719cd9647a1SBrian Somers 720479508cfSBrian Somers fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS; 721479508cfSBrian Somers switch (what) { 722479508cfSBrian Somers case FSM_REQ_TIMER: 723479508cfSBrian Somers fp->restart = ipcp->cfg.fsm.maxreq; 724479508cfSBrian Somers break; 725479508cfSBrian Somers case FSM_TRM_TIMER: 726479508cfSBrian Somers fp->restart = ipcp->cfg.fsm.maxtrm; 727479508cfSBrian Somers break; 728479508cfSBrian Somers default: 729479508cfSBrian Somers fp->restart = 1; 730479508cfSBrian Somers break; 731479508cfSBrian Somers } 732af57ed9fSAtsushi Murai } 733af57ed9fSAtsushi Murai 734af57ed9fSAtsushi Murai static void 735944f7098SBrian Somers IpcpSendConfigReq(struct fsm *fp) 736af57ed9fSAtsushi Murai { 7377308ec68SBrian Somers /* Send config REQ please */ 7388c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 739aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 7403edeb0c6SBrian Somers u_char buff[24]; 7412267893fSBrian Somers struct lcp_opt *o; 742af57ed9fSAtsushi Murai 7432267893fSBrian Somers o = (struct lcp_opt *)buff; 74430c2f2ffSBrian Somers 745dd7e2610SBrian Somers if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 7469e8ec64bSBrian Somers memcpy(o->data, &ipcp->my_ip.s_addr, 4); 7472267893fSBrian Somers INC_LCP_OPT(TY_IPADDR, 6, o); 7480053cc58SBrian Somers } 7490053cc58SBrian Somers 750e43ebac1SBrian Somers if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 75183d1af55SBrian Somers if (ipcp->heis1172) { 7529e8ec64bSBrian Somers u_int16_t proto = PROTO_VJCOMP; 7539e8ec64bSBrian Somers 7549e8ec64bSBrian Somers ua_htons(&proto, o->data); 7552267893fSBrian Somers INC_LCP_OPT(TY_COMPPROTO, 4, o); 7560053cc58SBrian Somers } else { 7577686a200SBrian Somers struct compreq req; 7587686a200SBrian Somers 7597686a200SBrian Somers req.proto = htons(ipcp->my_compproto >> 16); 7607686a200SBrian Somers req.slots = (ipcp->my_compproto >> 8) & 255; 7617686a200SBrian Somers req.compcid = ipcp->my_compproto & 1; 7627686a200SBrian Somers memcpy(o->data, &req, 4); 7632267893fSBrian Somers INC_LCP_OPT(TY_COMPPROTO, 6, o); 7640053cc58SBrian Somers } 765af57ed9fSAtsushi Murai } 7662267893fSBrian Somers 7673edeb0c6SBrian Somers if (IsEnabled(ipcp->cfg.ns.dns_neg) && 7683edeb0c6SBrian Somers !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && 7693edeb0c6SBrian Somers !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { 7703edeb0c6SBrian Somers struct in_addr dns[2]; 7713edeb0c6SBrian Somers getdns(ipcp, dns); 7729e8ec64bSBrian Somers memcpy(o->data, &dns[0].s_addr, 4); 7733edeb0c6SBrian Somers INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); 7749e8ec64bSBrian Somers memcpy(o->data, &dns[1].s_addr, 4); 7753edeb0c6SBrian Somers INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); 7763edeb0c6SBrian Somers } 7773edeb0c6SBrian Somers 778411675baSBrian Somers fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 779411675baSBrian Somers MB_IPCPOUT); 780af57ed9fSAtsushi Murai } 781af57ed9fSAtsushi Murai 782af57ed9fSAtsushi Murai static void 7832267893fSBrian Somers IpcpSentTerminateReq(struct fsm *fp) 784af57ed9fSAtsushi Murai { 7857308ec68SBrian Somers /* Term REQ just sent by FSM */ 786af57ed9fSAtsushi Murai } 787af57ed9fSAtsushi Murai 788af57ed9fSAtsushi Murai static void 7892267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id) 790af57ed9fSAtsushi Murai { 7917308ec68SBrian Somers /* Send Term ACK please */ 792411675baSBrian Somers fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT); 793af57ed9fSAtsushi Murai } 794af57ed9fSAtsushi Murai 795af57ed9fSAtsushi Murai static void 796944f7098SBrian Somers IpcpLayerStart(struct fsm *fp) 797af57ed9fSAtsushi Murai { 7987308ec68SBrian Somers /* We're about to start up ! */ 799897f9429SBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 800897f9429SBrian Somers 8013a2e4f62SBrian Somers log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name); 802897f9429SBrian Somers throughput_start(&ipcp->throughput, "IPCP throughput", 803897f9429SBrian Somers Enabled(fp->bundle, OPT_THROUGHPUT)); 804479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 805af57ed9fSAtsushi Murai } 806af57ed9fSAtsushi Murai 807af57ed9fSAtsushi Murai static void 808944f7098SBrian Somers IpcpLayerFinish(struct fsm *fp) 809af57ed9fSAtsushi Murai { 8107308ec68SBrian Somers /* We're now down */ 811897f9429SBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 812897f9429SBrian Somers 8133a2e4f62SBrian Somers log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name); 814897f9429SBrian Somers throughput_stop(&ipcp->throughput); 815897f9429SBrian Somers throughput_log(&ipcp->throughput, LogIPCP, NULL); 8161ae349f5Scvs2svn } 8171ae349f5Scvs2svn 81868a0f0ccSBrian Somers void 819dd7e2610SBrian Somers ipcp_CleanInterface(struct ipcp *ipcp) 82068a0f0ccSBrian Somers { 8218fa6ebe4SBrian Somers struct iface *iface = ipcp->fsm.bundle->iface; 82268a0f0ccSBrian Somers 823610b185fSBrian Somers route_Clean(ipcp->fsm.bundle, ipcp->route); 824610b185fSBrian Somers 8253afe5ccbSBrian Somers if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) || 8263afe5ccbSBrian Somers Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) { 8278fa6ebe4SBrian Somers int s = ID0socket(AF_INET, SOCK_DGRAM, 0); 8288fa6ebe4SBrian Somers if (s < 0) 8298fa6ebe4SBrian Somers log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", 83068a0f0ccSBrian Somers strerror(errno)); 8318fa6ebe4SBrian Somers else { 8323afe5ccbSBrian Somers if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL)) 8333afe5ccbSBrian Somers ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s); 8343afe5ccbSBrian Somers else if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) 8358fa6ebe4SBrian Somers arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s); 8368fa6ebe4SBrian Somers close(s); 8378fa6ebe4SBrian Somers } 83868a0f0ccSBrian Somers } 83968a0f0ccSBrian Somers 8408fa6ebe4SBrian Somers iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL); 841af57ed9fSAtsushi Murai } 842af57ed9fSAtsushi Murai 843af57ed9fSAtsushi Murai static void 844944f7098SBrian Somers IpcpLayerDown(struct fsm *fp) 845af57ed9fSAtsushi Murai { 8467308ec68SBrian Somers /* About to come down */ 847aa857470SBrian Somers static int recursing; 848aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 849455aabc3SBrian Somers const char *s; 850455aabc3SBrian Somers 851aa857470SBrian Somers if (!recursing++) { 8528fa6ebe4SBrian Somers if (ipcp->fsm.bundle->iface->in_addrs) 8538fa6ebe4SBrian Somers s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa); 8548fa6ebe4SBrian Somers else 8558fa6ebe4SBrian Somers s = "Interface configuration error !"; 8563a2e4f62SBrian Somers log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s); 857455aabc3SBrian Somers 858455aabc3SBrian Somers /* 859455aabc3SBrian Somers * XXX this stuff should really live in the FSM. Our config should 860455aabc3SBrian Somers * associate executable sections in files with events. 861455aabc3SBrian Somers */ 86230291ffbSBrian Somers if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) { 86349052c95SBrian Somers if (bundle_GetLabel(fp->bundle)) { 864dd7e2610SBrian Somers if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 86530291ffbSBrian Somers LINKDOWNFILE, NULL, NULL) < 0) 86630291ffbSBrian Somers system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 867455aabc3SBrian Somers } else 86830291ffbSBrian Somers system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 869af57ed9fSAtsushi Murai } 870af57ed9fSAtsushi Murai 871972a1bcfSBrian Somers ipcp_Setup(ipcp, INADDR_NONE); 8721ae349f5Scvs2svn } 873aa857470SBrian Somers recursing--; 874aa857470SBrian Somers } 8751ae349f5Scvs2svn 876dd0645c5SBrian Somers int 877dd0645c5SBrian Somers ipcp_InterfaceUp(struct ipcp *ipcp) 878dd0645c5SBrian Somers { 879dd0645c5SBrian Somers if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { 880a33b2ef7SBrian Somers log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n"); 881dd0645c5SBrian Somers return 0; 882dd0645c5SBrian Somers } 883dd0645c5SBrian Somers 88467b072f7SBrian Somers #ifndef NONAT 88567b072f7SBrian Somers if (ipcp->fsm.bundle->NatEnabled) 886615ad4f9SBrian Somers PacketAliasSetAddress(ipcp->my_ip); 887dd0645c5SBrian Somers #endif 888dd0645c5SBrian Somers 889dd0645c5SBrian Somers return 1; 890dd0645c5SBrian Somers } 891dd0645c5SBrian Somers 8926f384573SBrian Somers static int 893944f7098SBrian Somers IpcpLayerUp(struct fsm *fp) 894af57ed9fSAtsushi Murai { 8957308ec68SBrian Somers /* We're now up */ 896aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 8978fa6ebe4SBrian Somers char tbuff[16]; 898af57ed9fSAtsushi Murai 8993a2e4f62SBrian Somers log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name); 9008fa6ebe4SBrian Somers snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip)); 9018fa6ebe4SBrian Somers log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n", 9028fa6ebe4SBrian Somers tbuff, inet_ntoa(ipcp->peer_ip)); 90303604f35SBrian Somers 904503a7782SBrian Somers if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 905eaa4df37SBrian Somers sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); 90603604f35SBrian Somers 907dd0645c5SBrian Somers if (!ipcp_InterfaceUp(ipcp)) 9086f384573SBrian Somers return 0; 909455aabc3SBrian Somers 910455aabc3SBrian Somers /* 911455aabc3SBrian Somers * XXX this stuff should really live in the FSM. Our config should 912455aabc3SBrian Somers * associate executable sections in files with events. 913455aabc3SBrian Somers */ 9148fa6ebe4SBrian Somers if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 91549052c95SBrian Somers if (bundle_GetLabel(fp->bundle)) { 916dd7e2610SBrian Somers if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 91730291ffbSBrian Somers LINKUPFILE, NULL, NULL) < 0) 91830291ffbSBrian Somers system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 919455aabc3SBrian Somers } else 92030291ffbSBrian Somers system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 921af57ed9fSAtsushi Murai } 922af57ed9fSAtsushi Murai 923479508cfSBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 9240f2f3eb3SBrian Somers log_DisplayPrompts(); 925479508cfSBrian Somers 9266f384573SBrian Somers return 1; 927af57ed9fSAtsushi Murai } 928af57ed9fSAtsushi Murai 929af57ed9fSAtsushi Murai static int 9308fa6ebe4SBrian Somers AcceptableAddr(const struct in_range *prange, struct in_addr ipaddr) 931af57ed9fSAtsushi Murai { 9327308ec68SBrian Somers /* Is the given IP in the given range ? */ 933057df964SBrian Somers return (prange->ipaddr.s_addr & prange->mask.s_addr) == 934057df964SBrian Somers (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 935af57ed9fSAtsushi Murai } 936af57ed9fSAtsushi Murai 937af57ed9fSAtsushi Murai static void 93830c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 93930c2f2ffSBrian Somers struct fsm_decode *dec) 940af57ed9fSAtsushi Murai { 9417308ec68SBrian Somers /* Deal with incoming PROTO_IPCP */ 9428fa6ebe4SBrian Somers struct iface *iface = fp->bundle->iface; 943aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 9448fa6ebe4SBrian Somers int type, length, gotdns, gotdnsnak, n; 945fe3125a0SBrian Somers u_int32_t compproto; 946af57ed9fSAtsushi Murai struct compreq *pcomp; 9473edeb0c6SBrian Somers struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; 94830c2f2ffSBrian Somers char tbuff[100], tbuff2[100]; 949af57ed9fSAtsushi Murai 9503edeb0c6SBrian Somers gotdns = 0; 9513edeb0c6SBrian Somers gotdnsnak = 0; 9523edeb0c6SBrian Somers dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; 953af57ed9fSAtsushi Murai 954af57ed9fSAtsushi Murai while (plen >= sizeof(struct fsmconfig)) { 955af57ed9fSAtsushi Murai type = *cp; 956af57ed9fSAtsushi Murai length = cp[1]; 957d47dceb8SBrian Somers 958d47dceb8SBrian Somers if (length == 0) { 959dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); 960d47dceb8SBrian Somers break; 961d47dceb8SBrian Somers } 962d47dceb8SBrian Somers 9639e836af5SBrian Somers if (type < NCFTYPES) 96470ee81ffSBrian Somers snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); 9659e836af5SBrian Somers else if (type > 128 && type < 128 + NCFTYPES128) 96670ee81ffSBrian Somers snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); 967af57ed9fSAtsushi Murai else 96870ee81ffSBrian Somers snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); 969af57ed9fSAtsushi Murai 970af57ed9fSAtsushi Murai switch (type) { 971af57ed9fSAtsushi Murai case TY_IPADDR: /* RFC1332 */ 9729e8ec64bSBrian Somers memcpy(&ipaddr.s_addr, cp + 2, 4); 973dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 974af57ed9fSAtsushi Murai 9759780ef31SBrian Somers switch (mode_type) { 976af57ed9fSAtsushi Murai case MODE_REQ: 977503a7782SBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 978f5fb6bd0SBrian Somers if (ipaddr.s_addr == INADDR_ANY || 979503a7782SBrian Somers iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || 98030c2f2ffSBrian Somers ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, 98130c2f2ffSBrian Somers ipaddr, 1)) { 982dd7e2610SBrian Somers log_Printf(LogIPCP, "%s: Address invalid or already in use\n", 983bcc332bdSBrian Somers inet_ntoa(ipaddr)); 9848390b576SBrian Somers /* 9858fa6ebe4SBrian Somers * If we've already had a valid address configured for the peer, 9868fa6ebe4SBrian Somers * try NAKing with that so that we don't have to upset things 9878fa6ebe4SBrian Somers * too much. 9888390b576SBrian Somers */ 9898fa6ebe4SBrian Somers for (n = 0; n < iface->in_addrs; n++) 9908fa6ebe4SBrian Somers if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd) 9918fa6ebe4SBrian Somers >=0) { 9928fa6ebe4SBrian Somers ipcp->peer_ip = iface->in_addr[n].brd; 9938fa6ebe4SBrian Somers break; 9948fa6ebe4SBrian Somers } 9958fa6ebe4SBrian Somers 9968fa6ebe4SBrian Somers if (n == iface->in_addrs) 9978390b576SBrian Somers /* Just pick an IP number from our list */ 998503a7782SBrian Somers ipcp->peer_ip = ChooseHisAddr 99930c2f2ffSBrian Somers (fp->bundle, ipcp->cfg.my_range.ipaddr); 10008390b576SBrian Somers 1001503a7782SBrian Somers if (ipcp->peer_ip.s_addr == INADDR_ANY) { 100230c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 100330c2f2ffSBrian Somers dec->rejend += length; 1004bcc332bdSBrian Somers } else { 100530c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 100630c2f2ffSBrian Somers memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2); 100730c2f2ffSBrian Somers dec->nakend += length; 1008bcc332bdSBrian Somers } 1009bcc332bdSBrian Somers break; 1010bcc332bdSBrian Somers } 1011503a7782SBrian Somers } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { 1012af57ed9fSAtsushi Murai /* 10138390b576SBrian Somers * If destination address is not acceptable, NAK with what we 1014944f7098SBrian Somers * want to use. 1015af57ed9fSAtsushi Murai */ 101630c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 10178fa6ebe4SBrian Somers for (n = 0; n < iface->in_addrs; n++) 10188fa6ebe4SBrian Somers if ((iface->in_addr[n].brd.s_addr & 10198fa6ebe4SBrian Somers ipcp->cfg.peer_range.mask.s_addr) 10208fa6ebe4SBrian Somers == (ipcp->cfg.peer_range.ipaddr.s_addr & 10218fa6ebe4SBrian Somers ipcp->cfg.peer_range.mask.s_addr)) { 10228390b576SBrian Somers /* We prefer the already-configured address */ 10238fa6ebe4SBrian Somers memcpy(dec->nakend + 2, &iface->in_addr[n].brd.s_addr, 10248fa6ebe4SBrian Somers length - 2); 10258fa6ebe4SBrian Somers break; 10268fa6ebe4SBrian Somers } 10278fa6ebe4SBrian Somers 10288fa6ebe4SBrian Somers if (n == iface->in_addrs) 102930c2f2ffSBrian Somers memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2); 10308fa6ebe4SBrian Somers 103130c2f2ffSBrian Somers dec->nakend += length; 1032af57ed9fSAtsushi Murai break; 1033af57ed9fSAtsushi Murai } 1034503a7782SBrian Somers ipcp->peer_ip = ipaddr; 103530c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 103630c2f2ffSBrian Somers dec->ackend += length; 1037af57ed9fSAtsushi Murai break; 10388fa6ebe4SBrian Somers 1039af57ed9fSAtsushi Murai case MODE_NAK: 1040503a7782SBrian Somers if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { 1041bcc332bdSBrian Somers /* Use address suggested by peer */ 104270ee81ffSBrian Somers snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 1043503a7782SBrian Somers inet_ntoa(ipcp->my_ip)); 1044dd7e2610SBrian Somers log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 1045503a7782SBrian Somers ipcp->my_ip = ipaddr; 10461d1fc017SBrian Somers bundle_AdjustFilters(fp->bundle, &ipcp->my_ip, NULL); 1047bcc332bdSBrian Somers } else { 1048dd7e2610SBrian Somers log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, 10498390b576SBrian Somers "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 1050dd7e2610SBrian Somers fsm_Close(&ipcp->fsm); 1051af57ed9fSAtsushi Murai } 1052af57ed9fSAtsushi Murai break; 10538fa6ebe4SBrian Somers 1054af57ed9fSAtsushi Murai case MODE_REJ: 1055503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 1056af57ed9fSAtsushi Murai break; 1057af57ed9fSAtsushi Murai } 1058af57ed9fSAtsushi Murai break; 10598fa6ebe4SBrian Somers 1060af57ed9fSAtsushi Murai case TY_COMPPROTO: 10617686a200SBrian Somers pcomp = (struct compreq *)(cp + 2); 10627686a200SBrian Somers compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 10637686a200SBrian Somers pcomp->compcid; 1064dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 1065af57ed9fSAtsushi Murai 10669780ef31SBrian Somers switch (mode_type) { 1067af57ed9fSAtsushi Murai case MODE_REQ: 10681342caedSBrian Somers if (!IsAccepted(ipcp->cfg.vj.neg)) { 106930c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 107030c2f2ffSBrian Somers dec->rejend += length; 1071af57ed9fSAtsushi Murai } else { 1072af57ed9fSAtsushi Murai switch (length) { 1073af57ed9fSAtsushi Murai case 4: /* RFC1172 */ 1074af57ed9fSAtsushi Murai if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 10757686a200SBrian Somers log_Printf(LogWARN, "Peer is speaking RFC1172 compression " 10767686a200SBrian Somers "protocol !\n"); 107783d1af55SBrian Somers ipcp->heis1172 = 1; 1078503a7782SBrian Somers ipcp->peer_compproto = compproto; 107930c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 108030c2f2ffSBrian Somers dec->ackend += length; 1081af57ed9fSAtsushi Murai } else { 108230c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 1083af57ed9fSAtsushi Murai pcomp->proto = htons(PROTO_VJCOMP); 108430c2f2ffSBrian Somers memcpy(dec->nakend+2, &pcomp, 2); 108530c2f2ffSBrian Somers dec->nakend += length; 1086af57ed9fSAtsushi Murai } 1087af57ed9fSAtsushi Murai break; 1088af57ed9fSAtsushi Murai case 6: /* RFC1332 */ 10897686a200SBrian Somers if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 10907686a200SBrian Somers if (pcomp->slots <= MAX_VJ_STATES 1091503a7782SBrian Somers && pcomp->slots >= MIN_VJ_STATES) { 10927686a200SBrian Somers /* Ok, we can do that */ 1093503a7782SBrian Somers ipcp->peer_compproto = compproto; 109483d1af55SBrian Somers ipcp->heis1172 = 0; 109530c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 109630c2f2ffSBrian Somers dec->ackend += length; 1097af57ed9fSAtsushi Murai } else { 10987686a200SBrian Somers /* Get as close as we can to what he wants */ 10997686a200SBrian Somers ipcp->heis1172 = 0; 11007686a200SBrian Somers memcpy(dec->nakend, cp, 2); 11017686a200SBrian Somers pcomp->slots = pcomp->slots < MIN_VJ_STATES ? 11027686a200SBrian Somers MIN_VJ_STATES : MAX_VJ_STATES; 11037686a200SBrian Somers memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 11047686a200SBrian Somers dec->nakend += length; 11057686a200SBrian Somers } 11067686a200SBrian Somers } else { 11077686a200SBrian Somers /* What we really want */ 110830c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 1109af57ed9fSAtsushi Murai pcomp->proto = htons(PROTO_VJCOMP); 1110503a7782SBrian Somers pcomp->slots = DEF_VJ_STATES; 11117686a200SBrian Somers pcomp->compcid = 1; 111230c2f2ffSBrian Somers memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 111330c2f2ffSBrian Somers dec->nakend += length; 1114af57ed9fSAtsushi Murai } 1115af57ed9fSAtsushi Murai break; 1116af57ed9fSAtsushi Murai default: 111730c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 111830c2f2ffSBrian Somers dec->rejend += length; 1119af57ed9fSAtsushi Murai break; 1120af57ed9fSAtsushi Murai } 1121af57ed9fSAtsushi Murai } 1122af57ed9fSAtsushi Murai break; 11238fa6ebe4SBrian Somers 1124af57ed9fSAtsushi Murai case MODE_NAK: 11257686a200SBrian Somers if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 11267686a200SBrian Somers if (pcomp->slots > MAX_VJ_STATES) 11277686a200SBrian Somers pcomp->slots = MAX_VJ_STATES; 11287686a200SBrian Somers else if (pcomp->slots < MIN_VJ_STATES) 11297686a200SBrian Somers pcomp->slots = MIN_VJ_STATES; 11307686a200SBrian Somers compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 11317686a200SBrian Somers pcomp->compcid; 11327686a200SBrian Somers } else 11337686a200SBrian Somers compproto = 0; 1134dd7e2610SBrian Somers log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 1135503a7782SBrian Somers tbuff, ipcp->my_compproto, compproto); 1136503a7782SBrian Somers ipcp->my_compproto = compproto; 1137af57ed9fSAtsushi Murai break; 11388fa6ebe4SBrian Somers 1139af57ed9fSAtsushi Murai case MODE_REJ: 1140503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 1141af57ed9fSAtsushi Murai break; 1142af57ed9fSAtsushi Murai } 1143af57ed9fSAtsushi Murai break; 11448fa6ebe4SBrian Somers 1145af57ed9fSAtsushi Murai case TY_IPADDRS: /* RFC1172 */ 11469e8ec64bSBrian Somers memcpy(&ipaddr.s_addr, cp + 2, 4); 11479e8ec64bSBrian Somers memcpy(&dstipaddr.s_addr, cp + 6, 4); 114870ee81ffSBrian Somers snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 1149dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 1150af57ed9fSAtsushi Murai 11519780ef31SBrian Somers switch (mode_type) { 1152af57ed9fSAtsushi Murai case MODE_REQ: 11535d9e6103SBrian Somers memcpy(dec->rejend, cp, length); 11545d9e6103SBrian Somers dec->rejend += length; 1155af57ed9fSAtsushi Murai break; 11568fa6ebe4SBrian Somers 1157af57ed9fSAtsushi Murai case MODE_NAK: 1158af57ed9fSAtsushi Murai case MODE_REJ: 1159af57ed9fSAtsushi Murai break; 1160af57ed9fSAtsushi Murai } 1161af57ed9fSAtsushi Murai break; 1162d8e55738SJordan K. Hubbard 11633edeb0c6SBrian Somers case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ 1164d8e55738SJordan K. Hubbard case TY_SECONDARY_DNS: 11659e8ec64bSBrian Somers memcpy(&ipaddr.s_addr, cp + 2, 4); 1166dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 11673edeb0c6SBrian Somers 11689780ef31SBrian Somers switch (mode_type) { 1169d8e55738SJordan K. Hubbard case MODE_REQ: 11703edeb0c6SBrian Somers if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { 11713edeb0c6SBrian Somers ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 117230c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 117330c2f2ffSBrian Somers dec->rejend += length; 1174d8e55738SJordan K. Hubbard break; 1175d8e55738SJordan K. Hubbard } 11763edeb0c6SBrian Somers if (!gotdns) { 11773edeb0c6SBrian Somers dns[0] = ipcp->cfg.ns.dns[0]; 11783edeb0c6SBrian Somers dns[1] = ipcp->cfg.ns.dns[1]; 11793edeb0c6SBrian Somers if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) 11803edeb0c6SBrian Somers getdns(ipcp, dns); 11813edeb0c6SBrian Somers gotdns = 1; 11823edeb0c6SBrian Somers } 11833edeb0c6SBrian Somers have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; 1184944f7098SBrian Somers 11853edeb0c6SBrian Somers if (ipaddr.s_addr != have_ip.s_addr) { 11861ae349f5Scvs2svn /* 11873edeb0c6SBrian Somers * The client has got the DNS stuff wrong (first request) so 11881ae349f5Scvs2svn * we'll tell 'em how it is 11891ae349f5Scvs2svn */ 119030c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ 11913edeb0c6SBrian Somers memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); 119230c2f2ffSBrian Somers dec->nakend += length; 11933edeb0c6SBrian Somers } else { 1194d8e55738SJordan K. Hubbard /* 1195944f7098SBrian Somers * Otherwise they have it right (this time) so we send a ack packet 1196944f7098SBrian Somers * back confirming it... end of story 1197d8e55738SJordan K. Hubbard */ 119830c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 119930c2f2ffSBrian Somers dec->ackend += length; 12003edeb0c6SBrian Somers } 1201d8e55738SJordan K. Hubbard break; 12028fa6ebe4SBrian Somers 1203d8e55738SJordan K. Hubbard case MODE_NAK: /* what does this mean?? */ 12043edeb0c6SBrian Somers if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 12053edeb0c6SBrian Somers gotdnsnak = 1; 12069e8ec64bSBrian Somers memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4); 12073edeb0c6SBrian Somers } 1208d8e55738SJordan K. Hubbard break; 12098fa6ebe4SBrian Somers 12103edeb0c6SBrian Somers case MODE_REJ: /* Can't do much, stop asking */ 12113edeb0c6SBrian Somers ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); 1212d8e55738SJordan K. Hubbard break; 1213d8e55738SJordan K. Hubbard } 1214d8e55738SJordan K. Hubbard break; 1215d8e55738SJordan K. Hubbard 12163edeb0c6SBrian Somers case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ 1217d8e55738SJordan K. Hubbard case TY_SECONDARY_NBNS: 12189e8ec64bSBrian Somers memcpy(&ipaddr.s_addr, cp + 2, 4); 1219dd7e2610SBrian Somers log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 12203edeb0c6SBrian Somers 12219780ef31SBrian Somers switch (mode_type) { 1222d8e55738SJordan K. Hubbard case MODE_REQ: 12233edeb0c6SBrian Somers have_ip.s_addr = 12243edeb0c6SBrian Somers ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; 12253edeb0c6SBrian Somers 12263edeb0c6SBrian Somers if (have_ip.s_addr == INADDR_ANY) { 1227dd7e2610SBrian Somers log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); 12283edeb0c6SBrian Somers ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 122930c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 123030c2f2ffSBrian Somers dec->rejend += length; 1231d8e55738SJordan K. Hubbard break; 1232d8e55738SJordan K. Hubbard } 12333edeb0c6SBrian Somers 12343edeb0c6SBrian Somers if (ipaddr.s_addr != have_ip.s_addr) { 123530c2f2ffSBrian Somers memcpy(dec->nakend, cp, 2); 12363edeb0c6SBrian Somers memcpy(dec->nakend+2, &have_ip.s_addr, length); 123730c2f2ffSBrian Somers dec->nakend += length; 12383edeb0c6SBrian Somers } else { 123930c2f2ffSBrian Somers memcpy(dec->ackend, cp, length); 124030c2f2ffSBrian Somers dec->ackend += length; 12413edeb0c6SBrian Somers } 1242d8e55738SJordan K. Hubbard break; 12438fa6ebe4SBrian Somers 1244d8e55738SJordan K. Hubbard case MODE_NAK: 1245dd7e2610SBrian Somers log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 1246d8e55738SJordan K. Hubbard break; 12478fa6ebe4SBrian Somers 1248d8e55738SJordan K. Hubbard case MODE_REJ: 1249dd7e2610SBrian Somers log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 1250d8e55738SJordan K. Hubbard break; 1251d8e55738SJordan K. Hubbard } 1252d8e55738SJordan K. Hubbard break; 1253d8e55738SJordan K. Hubbard 1254af57ed9fSAtsushi Murai default: 125530c2f2ffSBrian Somers if (mode_type != MODE_NOP) { 125683d1af55SBrian Somers ipcp->my_reject |= (1 << type); 125730c2f2ffSBrian Somers memcpy(dec->rejend, cp, length); 125830c2f2ffSBrian Somers dec->rejend += length; 125930c2f2ffSBrian Somers } 1260af57ed9fSAtsushi Murai break; 1261af57ed9fSAtsushi Murai } 1262af57ed9fSAtsushi Murai plen -= length; 1263af57ed9fSAtsushi Murai cp += length; 1264af57ed9fSAtsushi Murai } 12651342caedSBrian Somers 12663edeb0c6SBrian Somers if (gotdnsnak) 12673edeb0c6SBrian Somers if (!setdns(ipcp, dnsnak)) { 12683edeb0c6SBrian Somers ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); 12693edeb0c6SBrian Somers ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); 12703edeb0c6SBrian Somers } 12713edeb0c6SBrian Somers 1272e43ebac1SBrian Somers if (mode_type != MODE_NOP) { 12731342caedSBrian Somers if (dec->rejend != dec->rej) { 12741342caedSBrian Somers /* rejects are preferred */ 12751342caedSBrian Somers dec->ackend = dec->ack; 12761342caedSBrian Somers dec->nakend = dec->nak; 12771342caedSBrian Somers } else if (dec->nakend != dec->nak) 12781342caedSBrian Somers /* then NAKs */ 12791342caedSBrian Somers dec->ackend = dec->ack; 12801ae349f5Scvs2svn } 1281af57ed9fSAtsushi Murai } 1282af57ed9fSAtsushi Murai 12835d9e6103SBrian Somers extern struct mbuf * 12845d9e6103SBrian Somers ipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 1285af57ed9fSAtsushi Murai { 12867308ec68SBrian Somers /* Got PROTO_IPCP from link */ 128726af0ae9SBrian Somers m_settype(bp, MB_IPCPIN); 1288641684cdSBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK) 12895d9e6103SBrian Somers fsm_Input(&bundle->ncp.ipcp.fsm, bp); 1290641684cdSBrian Somers else { 1291641684cdSBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK) 1292641684cdSBrian Somers log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", 12935d9e6103SBrian Somers l->name, bundle_PhaseName(bundle)); 129426af0ae9SBrian Somers m_freem(bp); 1295641684cdSBrian Somers } 12965d9e6103SBrian Somers return NULL; 1297af57ed9fSAtsushi Murai } 12989c97abd8SBrian Somers 12999c97abd8SBrian Somers int 1300972a1bcfSBrian Somers ipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr) 1301972a1bcfSBrian Somers { 1302972a1bcfSBrian Somers struct ipcp *ipcp = &bundle->ncp.ipcp; 1303972a1bcfSBrian Somers 1304972a1bcfSBrian Somers memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 1305972a1bcfSBrian Somers iplist_reset(&ipcp->cfg.peer_list); 1306972a1bcfSBrian Somers ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr; 1307972a1bcfSBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 1308972a1bcfSBrian Somers ipcp->cfg.peer_range.width = 32; 1309972a1bcfSBrian Somers 1310972a1bcfSBrian Somers if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0) 1311972a1bcfSBrian Somers return 0; 1312972a1bcfSBrian Somers 1313972a1bcfSBrian Somers return 1; /* Ok */ 1314972a1bcfSBrian Somers } 1315972a1bcfSBrian Somers 1316972a1bcfSBrian Somers int 1317dd7e2610SBrian Somers ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 13189c97abd8SBrian Somers { 13195828db6dSBrian Somers struct ipcp *ipcp = &bundle->ncp.ipcp; 13205828db6dSBrian Somers 13217308ec68SBrian Somers /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 13225828db6dSBrian Somers memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 13235828db6dSBrian Somers iplist_reset(&ipcp->cfg.peer_list); 13249c97abd8SBrian Somers if (strpbrk(hisaddr, ",-")) { 13255828db6dSBrian Somers iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); 13265828db6dSBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 13275828db6dSBrian Somers iplist_setrandpos(&ipcp->cfg.peer_list); 132830c2f2ffSBrian Somers ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); 13295828db6dSBrian Somers if (ipcp->peer_ip.s_addr == INADDR_ANY) { 1330dd7e2610SBrian Somers log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); 13311d1fc017SBrian Somers return 0; 13329c97abd8SBrian Somers } 13335828db6dSBrian Somers ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; 13345828db6dSBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 13355828db6dSBrian Somers ipcp->cfg.peer_range.width = 32; 13369c97abd8SBrian Somers } else { 1337dd7e2610SBrian Somers log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); 13389c97abd8SBrian Somers return 0; 13399c97abd8SBrian Somers } 1340972a1bcfSBrian Somers } else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr, 13415828db6dSBrian Somers &ipcp->cfg.peer_range.mask, 13425828db6dSBrian Somers &ipcp->cfg.peer_range.width) != 0) { 13435828db6dSBrian Somers ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; 13449c97abd8SBrian Somers 134530c2f2ffSBrian Somers if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, 13468fa6ebe4SBrian Somers ipcp->cfg.peer_range.ipaddr, 0) < 0) 13479c97abd8SBrian Somers return 0; 13489c97abd8SBrian Somers } else 13499c97abd8SBrian Somers return 0; 13509c97abd8SBrian Somers 13511d1fc017SBrian Somers bundle_AdjustFilters(bundle, NULL, &ipcp->peer_ip); 13521d1fc017SBrian Somers 13531d1fc017SBrian Somers return 1; /* Ok */ 13549c97abd8SBrian Somers } 1355bc76350eSBrian Somers 1356bc76350eSBrian Somers struct in_addr 1357bc76350eSBrian Somers addr2mask(struct in_addr addr) 1358bc76350eSBrian Somers { 1359bc76350eSBrian Somers u_int32_t haddr = ntohl(addr.s_addr); 1360bc76350eSBrian Somers 1361bc76350eSBrian Somers haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET : 1362bc76350eSBrian Somers IN_CLASSB(haddr) ? IN_CLASSB_NET : 1363bc76350eSBrian Somers IN_CLASSC_NET; 1364bc76350eSBrian Somers addr.s_addr = htonl(haddr); 1365bc76350eSBrian Somers 1366bc76350eSBrian Somers return addr; 1367bc76350eSBrian Somers } 1368