ipcp.c revision 81739
178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD: head/usr.sbin/ppp/ipcp.c 81739 2001-08-16 02:01:05Z brian $ 296059Samurai */ 3078189Sbrian 3130715Sbrian#include <sys/param.h> 326059Samurai#include <netinet/in_systm.h> 3329048Sbrian#include <netinet/in.h> 346059Samurai#include <netinet/ip.h> 356059Samurai#include <arpa/inet.h> 366059Samurai#include <sys/socket.h> 3776492Sbrian#include <net/if.h> 3840665Sbrian#include <net/route.h> 3930715Sbrian#include <netdb.h> 4036285Sbrian#include <sys/un.h> 4130715Sbrian 4246085Sbrian#include <errno.h> 4336285Sbrian#include <fcntl.h> 4436285Sbrian#include <resolv.h> 4532614Sbrian#include <stdlib.h> 4630715Sbrian#include <string.h> 4758044Sbrian#include <sys/stat.h> 4836285Sbrian#include <termios.h> 4930715Sbrian#include <unistd.h> 5030715Sbrian 5150059Sbrian#ifndef NONAT 5258037Sbrian#ifdef LOCALNAT 5358037Sbrian#include "alias.h" 5458037Sbrian#else 5546086Sbrian#include <alias.h> 5639395Sbrian#endif 5739395Sbrian#endif 5858037Sbrian 5946686Sbrian#include "layer.h" 6038814Sbrian#include "ua.h" 6137009Sbrian#include "defs.h" 6231343Sbrian#include "command.h" 6330715Sbrian#include "mbuf.h" 6430715Sbrian#include "log.h" 6530715Sbrian#include "timer.h" 6629048Sbrian#include "fsm.h" 6746686Sbrian#include "proto.h" 6831690Sbrian#include "iplist.h" 6936285Sbrian#include "throughput.h" 7036285Sbrian#include "slcompress.h" 7138557Sbrian#include "lqr.h" 7238557Sbrian#include "hdlc.h" 7363484Sbrian#include "lcp.h" 7481634Sbrian#include "ncpaddr.h" 7581634Sbrian#include "ip.h" 7629048Sbrian#include "ipcp.h" 7736285Sbrian#include "filter.h" 7836285Sbrian#include "descriptor.h" 7930715Sbrian#include "vjcomp.h" 8036285Sbrian#include "async.h" 8136285Sbrian#include "ccp.h" 8236285Sbrian#include "link.h" 8336285Sbrian#include "physical.h" 8436285Sbrian#include "mp.h" 8543313Sbrian#ifndef NORADIUS 8643313Sbrian#include "radius.h" 8743313Sbrian#endif 8881634Sbrian#include "ipv6cp.h" 8981634Sbrian#include "ncp.h" 9036285Sbrian#include "bundle.h" 9136285Sbrian#include "id.h" 9236285Sbrian#include "arp.h" 9336285Sbrian#include "systems.h" 9436285Sbrian#include "prompt.h" 9531690Sbrian#include "route.h" 9640561Sbrian#include "iface.h" 976059Samurai 9836285Sbrian#undef REJECTED 9936285Sbrian#define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) 10036285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t') 10136285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.') 1026059Samurai 10336285Sbrianstruct compreq { 10436285Sbrian u_short proto; 10536285Sbrian u_char slots; 10636285Sbrian u_char compcid; 10736285Sbrian}; 1086059Samurai 10936285Sbrianstatic int IpcpLayerUp(struct fsm *); 11036285Sbrianstatic void IpcpLayerDown(struct fsm *); 11126516Sbrianstatic void IpcpLayerStart(struct fsm *); 11226516Sbrianstatic void IpcpLayerFinish(struct fsm *); 11344305Sbrianstatic void IpcpInitRestartCounter(struct fsm *, int); 11436285Sbrianstatic void IpcpSendConfigReq(struct fsm *); 11536285Sbrianstatic void IpcpSentTerminateReq(struct fsm *); 11636285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char); 11736285Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, int, int, 11836285Sbrian struct fsm_decode *); 1196059Samurai 12036285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = { 1216059Samurai IpcpLayerUp, 1226059Samurai IpcpLayerDown, 1236059Samurai IpcpLayerStart, 1246059Samurai IpcpLayerFinish, 1256059Samurai IpcpInitRestartCounter, 1266059Samurai IpcpSendConfigReq, 12736285Sbrian IpcpSentTerminateReq, 1286059Samurai IpcpSendTerminateAck, 1296059Samurai IpcpDecodeConfig, 13036285Sbrian fsm_NullRecvResetReq, 13136285Sbrian fsm_NullRecvResetAck 1326059Samurai}; 1336059Samurai 13458034Sbrianstatic const char * 13558034Sbrianprotoname(int proto) 13658034Sbrian{ 13758034Sbrian static struct { 13858034Sbrian int id; 13958034Sbrian const char *txt; 14058034Sbrian } cftypes[] = { 14158034Sbrian /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 14258034Sbrian { 1, "IPADDRS" }, /* IP-Addresses */ /* deprecated */ 14358034Sbrian { 2, "COMPPROTO" }, /* IP-Compression-Protocol */ 14458034Sbrian { 3, "IPADDR" }, /* IP-Address */ 14558034Sbrian { 129, "PRIDNS" }, /* 129: Primary DNS Server Address */ 14658034Sbrian { 130, "PRINBNS" }, /* 130: Primary NBNS Server Address */ 14758034Sbrian { 131, "SECDNS" }, /* 131: Secondary DNS Server Address */ 14858034Sbrian { 132, "SECNBNS" } /* 132: Secondary NBNS Server Address */ 14958034Sbrian }; 15058034Sbrian int f; 1516059Samurai 15258034Sbrian for (f = 0; f < sizeof cftypes / sizeof *cftypes; f++) 15358034Sbrian if (cftypes[f].id == proto) 15458034Sbrian return cftypes[f].txt; 15531171Sbrian 15658034Sbrian return NumStr(proto, NULL, 0); 15758034Sbrian} 15831171Sbrian 15931272Sbrianvoid 16036285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n) 1616059Samurai{ 16236285Sbrian throughput_addin(&ipcp->throughput, n); 1636059Samurai} 1646059Samurai 16531272Sbrianvoid 16636285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n) 1676059Samurai{ 16836285Sbrian throughput_addout(&ipcp->throughput, n); 1696059Samurai} 1706059Samurai 17158044Sbrianvoid 17258044Sbrianipcp_LoadDNS(struct ipcp *ipcp) 1736059Samurai{ 17458044Sbrian int fd; 1756059Samurai 17658044Sbrian ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr = INADDR_NONE; 17736285Sbrian 17858044Sbrian if (ipcp->ns.resolv != NULL) { 17958044Sbrian free(ipcp->ns.resolv); 18058044Sbrian ipcp->ns.resolv = NULL; 18132614Sbrian } 18258044Sbrian if (ipcp->ns.resolv_nons != NULL) { 18358044Sbrian free(ipcp->ns.resolv_nons); 18458044Sbrian ipcp->ns.resolv_nons = NULL; 18558044Sbrian } 18658044Sbrian ipcp->ns.resolver = 0; 18729048Sbrian 18858044Sbrian if ((fd = open(_PATH_RESCONF, O_RDONLY)) != -1) { 18958044Sbrian struct stat st; 19026516Sbrian 19158044Sbrian if (fstat(fd, &st) == 0) { 19258044Sbrian ssize_t got; 19331272Sbrian 19458044Sbrian if ((ipcp->ns.resolv_nons = (char *)malloc(st.st_size + 1)) == NULL) 19558044Sbrian log_Printf(LogERROR, "Failed to malloc %lu for %s: %s\n", 19658044Sbrian (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno)); 19758044Sbrian else if ((ipcp->ns.resolv = (char *)malloc(st.st_size + 1)) == NULL) { 19858044Sbrian log_Printf(LogERROR, "Failed(2) to malloc %lu for %s: %s\n", 19958044Sbrian (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno)); 20058044Sbrian free(ipcp->ns.resolv_nons); 20158044Sbrian ipcp->ns.resolv_nons = NULL; 20258044Sbrian } else if ((got = read(fd, ipcp->ns.resolv, st.st_size)) != st.st_size) { 20358044Sbrian if (got == -1) 20458044Sbrian log_Printf(LogERROR, "Failed to read %s: %s\n", 20558044Sbrian _PATH_RESCONF, strerror(errno)); 20658044Sbrian else 20758044Sbrian log_Printf(LogERROR, "Failed to read %s, got %lu not %lu\n", 20858044Sbrian _PATH_RESCONF, (unsigned long)got, 20958044Sbrian (unsigned long)st.st_size); 21058044Sbrian free(ipcp->ns.resolv_nons); 21158044Sbrian ipcp->ns.resolv_nons = NULL; 21258044Sbrian free(ipcp->ns.resolv); 21358044Sbrian ipcp->ns.resolv = NULL; 21458044Sbrian } else { 21558044Sbrian char *cp, *cp_nons, *ncp, ch; 21658044Sbrian int n; 21736285Sbrian 21858044Sbrian ipcp->ns.resolv[st.st_size] = '\0'; 21958044Sbrian ipcp->ns.resolver = 1; 22036285Sbrian 22158044Sbrian cp_nons = ipcp->ns.resolv_nons; 22258044Sbrian cp = ipcp->ns.resolv; 22358044Sbrian n = 0; 22436285Sbrian 22558044Sbrian while ((ncp = strstr(cp, "nameserver")) != NULL) { 22658044Sbrian if (ncp != cp) { 22758044Sbrian memcpy(cp_nons, cp, ncp - cp); 22858044Sbrian cp_nons += ncp - cp; 22958044Sbrian } 23058044Sbrian if ((ncp != cp && ncp[-1] != '\n') || !issep(ncp[10])) { 23158044Sbrian memcpy(cp_nons, ncp, 9); 23258044Sbrian cp_nons += 9; 23358044Sbrian cp = ncp + 9; /* Can't match "nameserver" at cp... */ 23458044Sbrian continue; 23558044Sbrian } 23658044Sbrian 23758044Sbrian for (cp = ncp + 11; issep(*cp); cp++) /* Skip whitespace */ 23858044Sbrian ; 23958044Sbrian 24058044Sbrian for (ncp = cp; isip(*ncp); ncp++) /* Jump over IP */ 24158044Sbrian ; 24258044Sbrian 24358044Sbrian ch = *ncp; 24458044Sbrian *ncp = '\0'; 24581634Sbrian if (n < 2 && inet_aton(cp, ipcp->ns.dns)) 24658044Sbrian n++; 24758044Sbrian *ncp = ch; 24858044Sbrian 24958044Sbrian if ((cp = strchr(ncp, '\n')) == NULL) /* Point at next line */ 25058044Sbrian cp = ncp + strlen(ncp); 25158044Sbrian else 25258044Sbrian cp++; 25336285Sbrian } 25458044Sbrian strcpy(cp_nons, cp); /* Copy the end - including the NUL */ 25558044Sbrian cp_nons += strlen(cp_nons) - 1; 25658044Sbrian while (cp_nons >= ipcp->ns.resolv_nons && *cp_nons == '\n') 25758044Sbrian *cp_nons-- = '\0'; 25858044Sbrian if (n == 2 && ipcp->ns.dns[0].s_addr == INADDR_ANY) { 25958044Sbrian ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr; 26058044Sbrian ipcp->ns.dns[1].s_addr = INADDR_ANY; 26158044Sbrian } 26281634Sbrian bundle_AdjustDNS(ipcp->fsm.bundle); 26336285Sbrian } 26458044Sbrian } else 26558044Sbrian log_Printf(LogERROR, "Failed to stat opened %s: %s\n", 26658044Sbrian _PATH_RESCONF, strerror(errno)); 26758044Sbrian 26858044Sbrian close(fd); 26936285Sbrian } 27058044Sbrian} 27136285Sbrian 27258044Sbrianint 27358044Sbrianipcp_WriteDNS(struct ipcp *ipcp) 27458044Sbrian{ 27558044Sbrian const char *paddr; 27658044Sbrian mode_t mask; 27758044Sbrian FILE *fp; 27858044Sbrian 27958044Sbrian if (ipcp->ns.dns[0].s_addr == INADDR_ANY && 28058044Sbrian ipcp->ns.dns[1].s_addr == INADDR_ANY) { 28158044Sbrian log_Printf(LogIPCP, "%s not modified: All nameservers NAKd\n", 28258044Sbrian _PATH_RESCONF); 28358044Sbrian return 0; 28436285Sbrian } 28536285Sbrian 28658044Sbrian if (ipcp->ns.dns[0].s_addr == INADDR_ANY) { 28758044Sbrian ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr; 28858044Sbrian ipcp->ns.dns[1].s_addr = INADDR_ANY; 28936285Sbrian } 29036285Sbrian 29160839Sbrian mask = umask(022); 29258044Sbrian if ((fp = ID0fopen(_PATH_RESCONF, "w")) != NULL) { 29358044Sbrian umask(mask); 29460922Sbrian if (ipcp->ns.resolv_nons) 29560839Sbrian fputs(ipcp->ns.resolv_nons, fp); 29658044Sbrian paddr = inet_ntoa(ipcp->ns.dns[0]); 29758044Sbrian log_Printf(LogIPCP, "Primary nameserver set to %s\n", paddr); 29858044Sbrian fprintf(fp, "\nnameserver %s\n", paddr); 29958044Sbrian if (ipcp->ns.dns[1].s_addr != INADDR_ANY && 30058044Sbrian ipcp->ns.dns[1].s_addr != INADDR_NONE && 30158044Sbrian ipcp->ns.dns[1].s_addr != ipcp->ns.dns[0].s_addr) { 30258044Sbrian paddr = inet_ntoa(ipcp->ns.dns[1]); 30358044Sbrian log_Printf(LogIPCP, "Secondary nameserver set to %s\n", paddr); 30458044Sbrian fprintf(fp, "nameserver %s\n", paddr); 30558044Sbrian } 30658044Sbrian if (fclose(fp) == EOF) { 30758044Sbrian log_Printf(LogERROR, "write(): Failed updating %s: %s\n", _PATH_RESCONF, 30858044Sbrian strerror(errno)); 30936285Sbrian return 0; 31036285Sbrian } 31158044Sbrian } else 31258044Sbrian umask(mask); 31336285Sbrian 31436285Sbrian return 1; 3156059Samurai} 3166059Samurai 31758044Sbrianvoid 31858044Sbrianipcp_RestoreDNS(struct ipcp *ipcp) 31958044Sbrian{ 32058044Sbrian if (ipcp->ns.resolver) { 32158044Sbrian ssize_t got; 32258044Sbrian size_t len; 32358044Sbrian int fd; 32458044Sbrian 32558044Sbrian if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_TRUNC, 0644)) != -1) { 32658044Sbrian len = strlen(ipcp->ns.resolv); 32758044Sbrian if ((got = write(fd, ipcp->ns.resolv, len)) != len) { 32858044Sbrian if (got == -1) 32958044Sbrian log_Printf(LogERROR, "Failed rewriting %s: write: %s\n", 33058044Sbrian _PATH_RESCONF, strerror(errno)); 33158044Sbrian else 33258044Sbrian log_Printf(LogERROR, "Failed rewriting %s: wrote %lu of %lu\n", 33358044Sbrian _PATH_RESCONF, (unsigned long)got, (unsigned long)len); 33458044Sbrian } 33558044Sbrian close(fd); 33658044Sbrian } else 33758044Sbrian log_Printf(LogERROR, "Failed rewriting %s: open: %s\n", _PATH_RESCONF, 33858044Sbrian strerror(errno)); 33958044Sbrian } else if (remove(_PATH_RESCONF) == -1) 34058044Sbrian log_Printf(LogERROR, "Failed removing %s: %s\n", _PATH_RESCONF, 34158044Sbrian strerror(errno)); 34258044Sbrian 34358044Sbrian} 34458044Sbrian 34536285Sbrianint 34636285Sbrianipcp_Show(struct cmdargs const *arg) 3476059Samurai{ 34836285Sbrian struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 3496059Samurai 35036285Sbrian prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, 35136285Sbrian State2Nam(ipcp->fsm.state)); 35236285Sbrian if (ipcp->fsm.state == ST_OPENED) { 35336285Sbrian prompt_Printf(arg->prompt, " His side: %s, %s\n", 35436285Sbrian inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); 35536285Sbrian prompt_Printf(arg->prompt, " My side: %s, %s\n", 35636285Sbrian inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); 35758042Sbrian prompt_Printf(arg->prompt, " Queued packets: %lu\n", 35881634Sbrian (unsigned long)ipcp_QueueLen(ipcp)); 3596059Samurai } 36036285Sbrian 36136285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 36244305Sbrian prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 36344305Sbrian " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout, 36444305Sbrian ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s", 36544305Sbrian ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s"); 36681634Sbrian prompt_Printf(arg->prompt, " My Address: %s\n", 36781634Sbrian ncprange_ntoa(&ipcp->cfg.my_range)); 36836285Sbrian if (ipcp->cfg.HaveTriggerAddress) 36944455Sbrian prompt_Printf(arg->prompt, " Trigger address: %s\n", 37036285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 37144455Sbrian 37244455Sbrian prompt_Printf(arg->prompt, " VJ compression: %s (%d slots %s slot " 37336285Sbrian "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), 37436285Sbrian ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); 37536285Sbrian 37636285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) 37736285Sbrian prompt_Printf(arg->prompt, " His Address: %s\n", 37836285Sbrian ipcp->cfg.peer_list.src); 37936285Sbrian else 38081634Sbrian prompt_Printf(arg->prompt, " His Address: %s\n", 38181634Sbrian ncprange_ntoa(&ipcp->cfg.peer_range)); 38236285Sbrian 38358044Sbrian prompt_Printf(arg->prompt, " DNS: %s", 38458044Sbrian ipcp->cfg.ns.dns[0].s_addr == INADDR_NONE ? 38558044Sbrian "none" : inet_ntoa(ipcp->cfg.ns.dns[0])); 38658044Sbrian if (ipcp->cfg.ns.dns[1].s_addr != INADDR_NONE) 38781634Sbrian prompt_Printf(arg->prompt, ", %s", 38881634Sbrian inet_ntoa(ipcp->cfg.ns.dns[1])); 38958044Sbrian prompt_Printf(arg->prompt, ", %s\n", 39036285Sbrian command_ShowNegval(ipcp->cfg.ns.dns_neg)); 39158044Sbrian prompt_Printf(arg->prompt, " Resolver DNS: %s", 39258044Sbrian ipcp->ns.dns[0].s_addr == INADDR_NONE ? 39358044Sbrian "none" : inet_ntoa(ipcp->ns.dns[0])); 39458044Sbrian if (ipcp->ns.dns[1].s_addr != INADDR_NONE && 39558044Sbrian ipcp->ns.dns[1].s_addr != ipcp->ns.dns[0].s_addr) 39681634Sbrian prompt_Printf(arg->prompt, ", %s", 39781634Sbrian inet_ntoa(ipcp->ns.dns[1])); 39858044Sbrian prompt_Printf(arg->prompt, "\n NetBIOS NS: %s, ", 39936285Sbrian inet_ntoa(ipcp->cfg.ns.nbns[0])); 40081693Sbrian prompt_Printf(arg->prompt, "%s\n\n", 40181634Sbrian inet_ntoa(ipcp->cfg.ns.nbns[1])); 40236285Sbrian 40336285Sbrian throughput_disp(&ipcp->throughput, arg->prompt); 40436285Sbrian 40536285Sbrian return 0; 4066059Samurai} 4076059Samurai 40832614Sbrianint 40936285Sbrianipcp_vjset(struct cmdargs const *arg) 41032614Sbrian{ 41136285Sbrian if (arg->argc != arg->argn+2) 41232614Sbrian return -1; 41336285Sbrian if (!strcasecmp(arg->argv[arg->argn], "slots")) { 41432614Sbrian int slots; 41532614Sbrian 41636285Sbrian slots = atoi(arg->argv[arg->argn+1]); 41732614Sbrian if (slots < 4 || slots > 16) 41832614Sbrian return 1; 41936285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slots = slots; 42032614Sbrian return 0; 42136285Sbrian } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { 42236285Sbrian if (!strcasecmp(arg->argv[arg->argn+1], "on")) 42336285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; 42436285Sbrian else if (!strcasecmp(arg->argv[arg->argn+1], "off")) 42536285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; 42632614Sbrian else 42732614Sbrian return 2; 42832614Sbrian return 0; 42932614Sbrian } 43032614Sbrian return -1; 43132614Sbrian} 43232614Sbrian 43336285Sbrianvoid 43436285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, 43536285Sbrian const struct fsm_parent *parent) 43632614Sbrian{ 43736285Sbrian struct hostent *hp; 43881634Sbrian struct in_addr host; 43974049Sbrian char name[MAXHOSTNAMELEN]; 44055146Sbrian static const char * const timer_names[] = 44136285Sbrian {"IPCP restart", "IPCP openmode", "IPCP stopped"}; 44236285Sbrian 44344305Sbrian fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP, 44436285Sbrian bundle, l, parent, &ipcp_Callbacks, timer_names); 44536285Sbrian 44636285Sbrian ipcp->cfg.vj.slots = DEF_VJ_STATES; 44736285Sbrian ipcp->cfg.vj.slotcomp = 1; 44836285Sbrian memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 44981634Sbrian 45081634Sbrian host.s_addr = htonl(INADDR_LOOPBACK); 45181634Sbrian ipcp->cfg.netmask.s_addr = INADDR_ANY; 45236285Sbrian if (gethostname(name, sizeof name) == 0) { 45336285Sbrian hp = gethostbyname(name); 45481634Sbrian if (hp && hp->h_addrtype == AF_INET && hp->h_length == sizeof host.s_addr) 45581634Sbrian memcpy(&host.s_addr, hp->h_addr, sizeof host.s_addr); 45632614Sbrian } 45781634Sbrian ncprange_setip4(&ipcp->cfg.my_range, host, ipcp->cfg.netmask); 45881634Sbrian ncprange_setip4(&ipcp->cfg.peer_range, ipcp->cfg.netmask, ipcp->cfg.netmask); 45981634Sbrian 46036285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, ""); 46136285Sbrian ipcp->cfg.HaveTriggerAddress = 0; 46236285Sbrian 46358044Sbrian ipcp->cfg.ns.dns[0].s_addr = INADDR_NONE; 46458044Sbrian ipcp->cfg.ns.dns[1].s_addr = INADDR_NONE; 46536285Sbrian ipcp->cfg.ns.dns_neg = 0; 46636285Sbrian ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; 46736285Sbrian ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; 46836285Sbrian 46944305Sbrian ipcp->cfg.fsm.timeout = DEF_FSMRETRY; 47044305Sbrian ipcp->cfg.fsm.maxreq = DEF_FSMTRIES; 47144305Sbrian ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES; 47236285Sbrian ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; 47336285Sbrian 47436285Sbrian memset(&ipcp->vj, '\0', sizeof ipcp->vj); 47536285Sbrian 47658044Sbrian ipcp->ns.resolv = NULL; 47758044Sbrian ipcp->ns.resolv_nons = NULL; 47858044Sbrian ipcp->ns.writable = 1; 47958044Sbrian ipcp_LoadDNS(ipcp); 48058044Sbrian 48149434Sbrian throughput_init(&ipcp->throughput, SAMPLE_PERIOD); 48238557Sbrian memset(ipcp->Queue, '\0', sizeof ipcp->Queue); 48343313Sbrian ipcp_Setup(ipcp, INADDR_NONE); 48432614Sbrian} 48532614Sbrian 4866059Samuraivoid 48750867Sbrianipcp_Destroy(struct ipcp *ipcp) 48850867Sbrian{ 48981634Sbrian throughput_destroy(&ipcp->throughput); 49081634Sbrian 49158044Sbrian if (ipcp->ns.resolv != NULL) { 49258044Sbrian free(ipcp->ns.resolv); 49358044Sbrian ipcp->ns.resolv = NULL; 49458044Sbrian } 49558044Sbrian if (ipcp->ns.resolv_nons != NULL) { 49658044Sbrian free(ipcp->ns.resolv_nons); 49758044Sbrian ipcp->ns.resolv_nons = NULL; 49858044Sbrian } 49950867Sbrian} 50050867Sbrian 50150867Sbrianvoid 50236285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l) 5036059Samurai{ 50436285Sbrian ipcp->fsm.link = l; 50536285Sbrian} 50636285Sbrian 50736285Sbrianvoid 50843313Sbrianipcp_Setup(struct ipcp *ipcp, u_int32_t mask) 50936285Sbrian{ 51040561Sbrian struct iface *iface = ipcp->fsm.bundle->iface; 51181634Sbrian struct ncpaddr ipaddr; 51281634Sbrian struct in_addr peer; 51340561Sbrian int pos, n; 51436285Sbrian 51536285Sbrian ipcp->fsm.open_mode = 0; 51643313Sbrian ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask; 51736285Sbrian 51836285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 51940561Sbrian /* Try to give the peer a previously configured IP address */ 52081634Sbrian for (n = 0; n < iface->addrs; n++) { 52181634Sbrian if (!ncpaddr_getip4(&iface->addr[n].peer, &peer)) 52281634Sbrian continue; 52381634Sbrian if ((pos = iplist_ip2pos(&ipcp->cfg.peer_list, peer)) != -1) { 52481634Sbrian ncpaddr_setip4(&ipaddr, iplist_setcurpos(&ipcp->cfg.peer_list, pos)); 52540561Sbrian break; 52640561Sbrian } 52740561Sbrian } 52881634Sbrian if (n == iface->addrs) 52940561Sbrian /* Ok, so none of 'em fit.... pick a random one */ 53081634Sbrian ncpaddr_setip4(&ipaddr, iplist_setrandpos(&ipcp->cfg.peer_list)); 53140561Sbrian 53281634Sbrian ncprange_sethost(&ipcp->cfg.peer_range, &ipaddr); 5336059Samurai } 5349440Samurai 53536285Sbrian ipcp->heis1172 = 0; 53680476Sbrian ipcp->peer_req = 0; 53781634Sbrian ncprange_getip4addr(&ipcp->cfg.peer_range, &ipcp->peer_ip); 53836285Sbrian ipcp->peer_compproto = 0; 53936285Sbrian 54036285Sbrian if (ipcp->cfg.HaveTriggerAddress) { 54136285Sbrian /* 54236285Sbrian * Some implementations of PPP require that we send a 54336285Sbrian * *special* value as our address, even though the rfc specifies 54436285Sbrian * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 54536285Sbrian */ 54636285Sbrian ipcp->my_ip = ipcp->cfg.TriggerAddress; 54736285Sbrian log_Printf(LogIPCP, "Using trigger address %s\n", 54836285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 54940561Sbrian } else { 55036285Sbrian /* 55140561Sbrian * Otherwise, if we've used an IP number before and it's still within 55240561Sbrian * the network specified on the ``set ifaddr'' line, we really 55340561Sbrian * want to keep that IP number so that we can keep any existing 55481634Sbrian * connections that are bound to that IP. 55536285Sbrian */ 55681634Sbrian for (n = 0; n < iface->addrs; n++) { 55781634Sbrian ncprange_getaddr(&iface->addr[n].ifa, &ipaddr); 55881634Sbrian if (ncprange_contains(&ipcp->cfg.my_range, &ipaddr)) { 55981634Sbrian ncpaddr_getip4(&ipaddr, &ipcp->my_ip); 56040561Sbrian break; 56140561Sbrian } 56281634Sbrian } 56381634Sbrian if (n == iface->addrs) 56481634Sbrian ncprange_getip4addr(&ipcp->cfg.my_range, &ipcp->my_ip); 56540561Sbrian } 56636285Sbrian 56743313Sbrian if (IsEnabled(ipcp->cfg.vj.neg) 56843313Sbrian#ifndef NORADIUS 56943313Sbrian || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj) 57043313Sbrian#endif 57143313Sbrian ) 57236285Sbrian ipcp->my_compproto = (PROTO_VJCOMP << 16) + 57336285Sbrian ((ipcp->cfg.vj.slots - 1) << 8) + 57436285Sbrian ipcp->cfg.vj.slotcomp; 57536285Sbrian else 57636285Sbrian ipcp->my_compproto = 0; 57736285Sbrian sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); 57836285Sbrian 57936285Sbrian ipcp->peer_reject = 0; 58036285Sbrian ipcp->my_reject = 0; 58158044Sbrian 58281634Sbrian /* Copy startup values into ipcp->ns.dns */ 58358044Sbrian if (ipcp->cfg.ns.dns[0].s_addr != INADDR_NONE) 58481634Sbrian memcpy(ipcp->ns.dns, ipcp->cfg.ns.dns, sizeof ipcp->ns.dns); 58581634Sbrian} 58658044Sbrian 58781634Sbrianstatic int 58881634Sbriannumaddresses(struct in_addr mask) 58981634Sbrian{ 59081634Sbrian u_int32_t bit, haddr; 59181634Sbrian int n; 59281634Sbrian 59381634Sbrian haddr = ntohl(mask.s_addr); 59481634Sbrian bit = 1; 59581634Sbrian n = 1; 59681634Sbrian 59781634Sbrian do { 59881634Sbrian if (!(haddr & bit)) 59981634Sbrian n <<= 1; 60081634Sbrian } while (bit <<= 1); 60181634Sbrian 60281634Sbrian return n; 60336285Sbrian} 60436285Sbrian 60536285Sbrianstatic int 60681634Sbrianipcp_proxyarp(struct ipcp *ipcp, 60781634Sbrian int (*proxyfun)(struct bundle *, struct in_addr, int), 60881634Sbrian const struct iface_addr *addr) 60940665Sbrian{ 61081634Sbrian struct bundle *bundle = ipcp->fsm.bundle; 61181634Sbrian struct in_addr peer, mask, ip; 61281634Sbrian int n, ret, s; 61340665Sbrian 61481634Sbrian if (!ncpaddr_getip4(&addr->peer, &peer)) { 61581634Sbrian log_Printf(LogERROR, "Oops, ipcp_proxyarp() called with unexpected addr\n"); 61681634Sbrian return 0; 61781634Sbrian } 61881634Sbrian 61981634Sbrian if ((s = ID0socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 62081634Sbrian log_Printf(LogERROR, "ipcp_proxyarp: socket: %s\n", 62181634Sbrian strerror(errno)); 62281634Sbrian return 0; 62381634Sbrian } 62481634Sbrian 62581634Sbrian ret = 0; 62681634Sbrian 62781634Sbrian if (Enabled(bundle, OPT_PROXYALL)) { 62881634Sbrian ncprange_getip4mask(&addr->ifa, &mask); 62981634Sbrian if ((n = numaddresses(mask)) > 256) { 63081634Sbrian log_Printf(LogWARN, "%s: Too many addresses for proxyall\n", 63181634Sbrian ncprange_ntoa(&addr->ifa)); 63281634Sbrian return 0; 63381634Sbrian } 63481634Sbrian ip.s_addr = peer.s_addr & mask.s_addr; 63581634Sbrian if (n >= 4) { 63681634Sbrian ip.s_addr = htonl(ntohl(ip.s_addr) + 1); 63781634Sbrian n -= 2; 63881634Sbrian } 63981634Sbrian while (n) { 64081634Sbrian if (!((ip.s_addr ^ peer.s_addr) & mask.s_addr)) { 64181634Sbrian if (!(ret = (*proxyfun)(bundle, ip, s))) 64281634Sbrian break; 64381634Sbrian n--; 64440665Sbrian } 64581634Sbrian ip.s_addr = htonl(ntohl(ip.s_addr) + 1); 64640665Sbrian } 64781634Sbrian ret = !n; 64881634Sbrian } else if (Enabled(bundle, OPT_PROXY)) 64981634Sbrian ret = (*proxyfun)(bundle, peer, s); 65040665Sbrian 65181634Sbrian close(s); 65281634Sbrian 65381634Sbrian return ret; 65440665Sbrian} 65540665Sbrian 65640665Sbrianstatic int 65781634Sbrianipcp_SetIPaddress(struct ipcp *ipcp, struct in_addr myaddr, 65881634Sbrian struct in_addr hisaddr) 65936285Sbrian{ 66081634Sbrian struct bundle *bundle = ipcp->fsm.bundle; 66181634Sbrian struct ncpaddr myncpaddr, hisncpaddr; 66281739Sbrian struct ncprange myrange; 66381634Sbrian struct in_addr mask; 66481739Sbrian struct sockaddr_storage ssdst, ssgw, ssmask; 66581739Sbrian struct sockaddr *sadst, *sagw, *samask; 66636285Sbrian 66781739Sbrian sadst = (struct sockaddr *)&ssdst; 66881739Sbrian sagw = (struct sockaddr *)&ssgw; 66981739Sbrian samask = (struct sockaddr *)&ssmask; 67081739Sbrian 67181634Sbrian ncpaddr_setip4(&hisncpaddr, hisaddr); 67281634Sbrian ncpaddr_setip4(&myncpaddr, myaddr); 67381634Sbrian ncprange_sethost(&myrange, &myncpaddr); 67481634Sbrian 67544455Sbrian mask = addr2mask(myaddr); 67636285Sbrian 67781634Sbrian if (ipcp->ifmask.s_addr != INADDR_ANY && 67881634Sbrian (ipcp->ifmask.s_addr & mask.s_addr) == mask.s_addr) 67981634Sbrian ncprange_setip4mask(&myrange, ipcp->ifmask); 68036285Sbrian 68181634Sbrian if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &hisncpaddr, 68281634Sbrian IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM)) 68381634Sbrian return 0; 68436285Sbrian 68581634Sbrian if (!Enabled(bundle, OPT_IFACEALIAS)) 68681634Sbrian iface_Clear(bundle->iface, &bundle->ncp, AF_INET, 68781634Sbrian IFACE_CLEAR_ALIASES|IFACE_SYSTEM); 68836285Sbrian 68981634Sbrian if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) { 69081739Sbrian ncprange_getsa(&myrange, &ssgw, &ssmask); 69181739Sbrian ncpaddr_getsa(&hisncpaddr, &ssdst); 69281739Sbrian rt_Update(bundle, sadst, sagw, samask); 69381634Sbrian } 69440665Sbrian 69536285Sbrian if (Enabled(bundle, OPT_SROUTES)) 69681634Sbrian route_Change(bundle, bundle->ncp.route, &myncpaddr, &hisncpaddr); 69736285Sbrian 69843313Sbrian#ifndef NORADIUS 69943313Sbrian if (bundle->radius.valid) 70081634Sbrian route_Change(bundle, bundle->radius.routes, &myncpaddr, &hisncpaddr); 70143313Sbrian#endif 70243313Sbrian 70381634Sbrian return 1; /* Ok */ 7046059Samurai} 7056059Samurai 70636285Sbrianstatic struct in_addr 70740561SbrianChooseHisAddr(struct bundle *bundle, struct in_addr gw) 70836285Sbrian{ 70936285Sbrian struct in_addr try; 71037210Sbrian u_long f; 71136285Sbrian 71236285Sbrian for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { 71336285Sbrian try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); 71437210Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n", 71536285Sbrian f, inet_ntoa(try)); 71681634Sbrian if (ipcp_SetIPaddress(&bundle->ncp.ipcp, gw, try)) { 71736285Sbrian log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); 71836285Sbrian break; 71936285Sbrian } 72036285Sbrian } 72136285Sbrian 72236285Sbrian if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { 72336285Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 72436285Sbrian try.s_addr = INADDR_ANY; 72536285Sbrian } 72636285Sbrian 72736285Sbrian return try; 72836285Sbrian} 72936285Sbrian 7306059Samuraistatic void 73144305SbrianIpcpInitRestartCounter(struct fsm *fp, int what) 7326059Samurai{ 73336285Sbrian /* Set fsm timer load */ 73436285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 73536285Sbrian 73644305Sbrian fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS; 73744305Sbrian switch (what) { 73844305Sbrian case FSM_REQ_TIMER: 73944305Sbrian fp->restart = ipcp->cfg.fsm.maxreq; 74044305Sbrian break; 74144305Sbrian case FSM_TRM_TIMER: 74244305Sbrian fp->restart = ipcp->cfg.fsm.maxtrm; 74344305Sbrian break; 74444305Sbrian default: 74544305Sbrian fp->restart = 1; 74644305Sbrian break; 74744305Sbrian } 7486059Samurai} 7496059Samurai 7506059Samuraistatic void 75136285SbrianIpcpSendConfigReq(struct fsm *fp) 7526059Samurai{ 75336285Sbrian /* Send config REQ please */ 75436285Sbrian struct physical *p = link2physical(fp->link); 75536285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 75636285Sbrian u_char buff[24]; 75736285Sbrian struct lcp_opt *o; 7586059Samurai 75936285Sbrian o = (struct lcp_opt *)buff; 76036285Sbrian 76136285Sbrian if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 76238814Sbrian memcpy(o->data, &ipcp->my_ip.s_addr, 4); 76336285Sbrian INC_LCP_OPT(TY_IPADDR, 6, o); 76431514Sbrian } 76531514Sbrian 76636285Sbrian if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 76736285Sbrian if (ipcp->heis1172) { 76838814Sbrian u_int16_t proto = PROTO_VJCOMP; 76938814Sbrian 77038814Sbrian ua_htons(&proto, o->data); 77136285Sbrian INC_LCP_OPT(TY_COMPPROTO, 4, o); 77231514Sbrian } else { 77343545Sbrian struct compreq req; 77443545Sbrian 77543545Sbrian req.proto = htons(ipcp->my_compproto >> 16); 77643545Sbrian req.slots = (ipcp->my_compproto >> 8) & 255; 77743545Sbrian req.compcid = ipcp->my_compproto & 1; 77843545Sbrian memcpy(o->data, &req, 4); 77936285Sbrian INC_LCP_OPT(TY_COMPPROTO, 6, o); 78031514Sbrian } 7816059Samurai } 78236285Sbrian 78381634Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 78481634Sbrian if (!REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS)) { 78581634Sbrian memcpy(o->data, &ipcp->ns.dns[0].s_addr, 4); 78681634Sbrian INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); 78781634Sbrian } 78871356Sbrian 78981634Sbrian if (!REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { 79081634Sbrian memcpy(o->data, &ipcp->ns.dns[1].s_addr, 4); 79181634Sbrian INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); 79281634Sbrian } 79336285Sbrian } 79436285Sbrian 79547695Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 79647695Sbrian MB_IPCPOUT); 7976059Samurai} 7986059Samurai 7996059Samuraistatic void 80044305SbrianIpcpSentTerminateReq(struct fsm *fp) 8016059Samurai{ 80236285Sbrian /* Term REQ just sent by FSM */ 8036059Samurai} 8046059Samurai 8056059Samuraistatic void 80636285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id) 8076059Samurai{ 80836285Sbrian /* Send Term ACK please */ 80947695Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT); 8106059Samurai} 8116059Samurai 8126059Samuraistatic void 81337160SbrianIpcpLayerStart(struct fsm *fp) 8146059Samurai{ 81536285Sbrian /* We're about to start up ! */ 81637160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 81737160Sbrian 81837210Sbrian log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name); 81937160Sbrian throughput_start(&ipcp->throughput, "IPCP throughput", 82037160Sbrian Enabled(fp->bundle, OPT_THROUGHPUT)); 82144305Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 82280476Sbrian ipcp->peer_req = 0; 8236059Samurai} 8246059Samurai 8256059Samuraistatic void 82636285SbrianIpcpLayerFinish(struct fsm *fp) 8276059Samurai{ 82836285Sbrian /* We're now down */ 82937160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 83037160Sbrian 83137210Sbrian log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name); 83237160Sbrian throughput_stop(&ipcp->throughput); 83337160Sbrian throughput_log(&ipcp->throughput, LogIPCP, NULL); 8346059Samurai} 8356059Samurai 83681634Sbrian/* 83781634Sbrian * Called from iface_Add() via ncp_IfaceAddrAdded() 83881634Sbrian */ 83936285Sbrianvoid 84081634Sbrianipcp_IfaceAddrAdded(struct ipcp *ipcp, const struct iface_addr *addr) 8416059Samurai{ 84281634Sbrian struct bundle *bundle = ipcp->fsm.bundle; 84336285Sbrian 84481634Sbrian if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) 84581634Sbrian ipcp_proxyarp(ipcp, arp_SetProxy, addr); 84681634Sbrian} 84736285Sbrian 84881634Sbrian/* 84981634Sbrian * Called from iface_Clear() and iface_Delete() via ncp_IfaceAddrDeleted() 85081634Sbrian */ 85181634Sbrianvoid 85281634Sbrianipcp_IfaceAddrDeleted(struct ipcp *ipcp, const struct iface_addr *addr) 85381634Sbrian{ 85481634Sbrian struct bundle *bundle = ipcp->fsm.bundle; 85581634Sbrian 85681634Sbrian if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) 85781634Sbrian ipcp_proxyarp(ipcp, arp_ClearProxy, addr); 8586059Samurai} 8596059Samurai 8606059Samuraistatic void 86136285SbrianIpcpLayerDown(struct fsm *fp) 8626059Samurai{ 86336285Sbrian /* About to come down */ 86481634Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 86547835Sbrian static int recursing; 86681634Sbrian char addr[16]; 8676059Samurai 86847835Sbrian if (!recursing++) { 86981634Sbrian snprintf(addr, sizeof addr, "%s", inet_ntoa(ipcp->my_ip)); 87081634Sbrian log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, addr); 87130187Sbrian 87265178Sbrian#ifndef NORADIUS 87365178Sbrian radius_Account(&fp->bundle->radius, &fp->bundle->radacct, 87465178Sbrian fp->bundle->links, RAD_STOP, &ipcp->peer_ip, &ipcp->ifmask, 87565178Sbrian &ipcp->throughput); 87665178Sbrian#endif 87765178Sbrian 87847835Sbrian /* 87947835Sbrian * XXX this stuff should really live in the FSM. Our config should 88047835Sbrian * associate executable sections in files with events. 88147835Sbrian */ 88281634Sbrian if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) { 88347835Sbrian if (bundle_GetLabel(fp->bundle)) { 88447835Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 88547835Sbrian LINKDOWNFILE, NULL, NULL) < 0) 88647835Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 88747835Sbrian } else 88847835Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 88947835Sbrian } 89047835Sbrian 89147835Sbrian ipcp_Setup(ipcp, INADDR_NONE); 89236285Sbrian } 89347835Sbrian recursing--; 89436285Sbrian} 89536285Sbrian 89636285Sbrianint 89736285Sbrianipcp_InterfaceUp(struct ipcp *ipcp) 89836285Sbrian{ 89981634Sbrian if (!ipcp_SetIPaddress(ipcp, ipcp->my_ip, ipcp->peer_ip)) { 90037019Sbrian log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n"); 90136285Sbrian return 0; 90225630Sbrian } 90336285Sbrian 90476492Sbrian if (!iface_SetFlags(ipcp->fsm.bundle->iface->name, IFF_UP)) { 90576492Sbrian log_Printf(LogERROR, "ipcp_InterfaceUp: Can't set the IFF_UP flag on %s\n", 90676492Sbrian ipcp->fsm.bundle->iface->name); 90776492Sbrian return 0; 90876492Sbrian } 90976492Sbrian 91050059Sbrian#ifndef NONAT 91150059Sbrian if (ipcp->fsm.bundle->NatEnabled) 91237191Sbrian PacketAliasSetAddress(ipcp->my_ip); 91331343Sbrian#endif 91436285Sbrian 91536285Sbrian return 1; 9166059Samurai} 9176059Samurai 91836285Sbrianstatic int 91936285SbrianIpcpLayerUp(struct fsm *fp) 9206059Samurai{ 92136285Sbrian /* We're now up */ 92236285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 92340561Sbrian char tbuff[16]; 9246059Samurai 92537210Sbrian log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name); 92640561Sbrian snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip)); 92740561Sbrian log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n", 92840561Sbrian tbuff, inet_ntoa(ipcp->peer_ip)); 92936285Sbrian 93036285Sbrian if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 93136285Sbrian sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); 93236285Sbrian 93336285Sbrian if (!ipcp_InterfaceUp(ipcp)) 93436285Sbrian return 0; 93536285Sbrian 93665178Sbrian#ifndef NORADIUS 93765178Sbrian radius_Account(&fp->bundle->radius, &fp->bundle->radacct, fp->bundle->links, 93865178Sbrian RAD_START, &ipcp->peer_ip, &ipcp->ifmask, &ipcp->throughput); 93965178Sbrian#endif 94065178Sbrian 94136285Sbrian /* 94236285Sbrian * XXX this stuff should really live in the FSM. Our config should 94336285Sbrian * associate executable sections in files with events. 94436285Sbrian */ 94540561Sbrian if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 94636285Sbrian if (bundle_GetLabel(fp->bundle)) { 94736285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 94837008Sbrian LINKUPFILE, NULL, NULL) < 0) 94937008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 95036285Sbrian } else 95137008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 95236285Sbrian } 95336285Sbrian 95444305Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 95536314Sbrian log_DisplayPrompts(); 95644305Sbrian 95736285Sbrian return 1; 9586059Samurai} 9596059Samurai 9606059Samuraistatic void 96176986Sbrianipcp_ValidateReq(struct ipcp *ipcp, struct in_addr ip, struct fsm_decode *dec) 96276986Sbrian{ 96376986Sbrian struct bundle *bundle = ipcp->fsm.bundle; 96476986Sbrian struct iface *iface = bundle->iface; 96581634Sbrian struct in_addr myaddr, peer; 96676986Sbrian int n; 96776986Sbrian 96876986Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 96981634Sbrian ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr); 97076986Sbrian if (ip.s_addr == INADDR_ANY || 97176986Sbrian iplist_ip2pos(&ipcp->cfg.peer_list, ip) < 0 || 97281634Sbrian !ipcp_SetIPaddress(ipcp, myaddr, ip)) { 97376986Sbrian log_Printf(LogIPCP, "%s: Address invalid or already in use\n", 97476986Sbrian inet_ntoa(ip)); 97576986Sbrian /* 97676986Sbrian * If we've already had a valid address configured for the peer, 97776986Sbrian * try NAKing with that so that we don't have to upset things 97876986Sbrian * too much. 97976986Sbrian */ 98081634Sbrian for (n = 0; n < iface->addrs; n++) { 98181634Sbrian if (!ncpaddr_getip4(&iface->addr[n].peer, &peer)) 98281634Sbrian continue; 98381634Sbrian if (iplist_ip2pos(&ipcp->cfg.peer_list, peer) >= 0) { 98481634Sbrian ipcp->peer_ip = peer; 98576986Sbrian break; 98676986Sbrian } 98781634Sbrian } 98876986Sbrian 98981634Sbrian if (n == iface->addrs) { 99076986Sbrian /* Just pick an IP number from our list */ 99181634Sbrian ipcp->peer_ip = ChooseHisAddr(bundle, myaddr); 99281634Sbrian } 99376986Sbrian 99476986Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 99576986Sbrian *dec->rejend++ = TY_IPADDR; 99676986Sbrian *dec->rejend++ = 6; 99776986Sbrian memcpy(dec->rejend, &ip.s_addr, 4); 99876986Sbrian dec->rejend += 4; 99976986Sbrian } else { 100076986Sbrian *dec->nakend++ = TY_IPADDR; 100176986Sbrian *dec->nakend++ = 6; 100276986Sbrian memcpy(dec->nakend, &ipcp->peer_ip.s_addr, 4); 100376986Sbrian dec->nakend += 4; 100476986Sbrian } 100576986Sbrian return; 100676986Sbrian } 100781634Sbrian } else if (!ncprange_containsip4(&ipcp->cfg.peer_range, ip)) { 100876986Sbrian /* 100976986Sbrian * If the destination address is not acceptable, NAK with what we 101076986Sbrian * want to use. 101176986Sbrian */ 101276986Sbrian *dec->nakend++ = TY_IPADDR; 101376986Sbrian *dec->nakend++ = 6; 101481634Sbrian for (n = 0; n < iface->addrs; n++) 101581634Sbrian if (ncprange_contains(&ipcp->cfg.peer_range, &iface->addr[n].peer)) { 101676986Sbrian /* We prefer the already-configured address */ 101781634Sbrian ncpaddr_getip4addr(&iface->addr[n].peer, (u_int32_t *)dec->nakend); 101876986Sbrian break; 101976986Sbrian } 102076986Sbrian 102181634Sbrian if (n == iface->addrs) 102276986Sbrian memcpy(dec->nakend, &ipcp->peer_ip.s_addr, 4); 102376986Sbrian 102476986Sbrian dec->nakend += 4; 102576986Sbrian return; 102676986Sbrian } 102776986Sbrian 102876986Sbrian ipcp->peer_ip = ip; 102976986Sbrian *dec->ackend++ = TY_IPADDR; 103076986Sbrian *dec->ackend++ = 6; 103176986Sbrian memcpy(dec->ackend, &ip.s_addr, 4); 103276986Sbrian dec->ackend += 4; 103376986Sbrian} 103476986Sbrian 103576986Sbrianstatic void 103646828SbrianIpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 103736285Sbrian struct fsm_decode *dec) 10386059Samurai{ 103936285Sbrian /* Deal with incoming PROTO_IPCP */ 104081634Sbrian struct ncpaddr ncpaddr; 104136285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 104280476Sbrian int type, length, gotdnsnak; 104336285Sbrian u_int32_t compproto; 10446059Samurai struct compreq *pcomp; 104558044Sbrian struct in_addr ipaddr, dstipaddr, have_ip; 104636285Sbrian char tbuff[100], tbuff2[100]; 10476059Samurai 104836285Sbrian gotdnsnak = 0; 10496059Samurai 10506059Samurai while (plen >= sizeof(struct fsmconfig)) { 10516059Samurai type = *cp; 10526059Samurai length = cp[1]; 105336285Sbrian 105436285Sbrian if (length == 0) { 105536285Sbrian log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); 105636285Sbrian break; 105736285Sbrian } 105836285Sbrian 105958034Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", protoname(type), length); 10606059Samurai 10616059Samurai switch (type) { 10626059Samurai case TY_IPADDR: /* RFC1332 */ 106338814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 106436285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 10656059Samurai 106631034Sbrian switch (mode_type) { 10676059Samurai case MODE_REQ: 106880476Sbrian ipcp->peer_req = 1; 106976986Sbrian ipcp_ValidateReq(ipcp, ipaddr, dec); 10706059Samurai break; 107140561Sbrian 10726059Samurai case MODE_NAK: 107381634Sbrian if (ncprange_containsip4(&ipcp->cfg.my_range, ipaddr)) { 107431690Sbrian /* Use address suggested by peer */ 107531962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 107636285Sbrian inet_ntoa(ipcp->my_ip)); 107736285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 107836285Sbrian ipcp->my_ip = ipaddr; 107981634Sbrian ncpaddr_setip4(&ncpaddr, ipcp->my_ip); 108081634Sbrian bundle_AdjustFilters(fp->bundle, &ncpaddr, NULL); 108131690Sbrian } else { 108236285Sbrian log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, 108336285Sbrian "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 108436285Sbrian fsm_Close(&ipcp->fsm); 10856059Samurai } 10866059Samurai break; 108740561Sbrian 10886059Samurai case MODE_REJ: 108936285Sbrian ipcp->peer_reject |= (1 << type); 10906059Samurai break; 10916059Samurai } 10926059Samurai break; 109340561Sbrian 10946059Samurai case TY_COMPPROTO: 109543545Sbrian pcomp = (struct compreq *)(cp + 2); 109643545Sbrian compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 109743545Sbrian pcomp->compcid; 109836285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 10996059Samurai 110031034Sbrian switch (mode_type) { 11016059Samurai case MODE_REQ: 110236285Sbrian if (!IsAccepted(ipcp->cfg.vj.neg)) { 110336285Sbrian memcpy(dec->rejend, cp, length); 110436285Sbrian dec->rejend += length; 11056059Samurai } else { 11066059Samurai switch (length) { 110728679Sbrian case 4: /* RFC1172 */ 11086059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 110943545Sbrian log_Printf(LogWARN, "Peer is speaking RFC1172 compression " 111043545Sbrian "protocol !\n"); 111136285Sbrian ipcp->heis1172 = 1; 111236285Sbrian ipcp->peer_compproto = compproto; 111336285Sbrian memcpy(dec->ackend, cp, length); 111436285Sbrian dec->ackend += length; 11156059Samurai } else { 111636285Sbrian memcpy(dec->nakend, cp, 2); 11176059Samurai pcomp->proto = htons(PROTO_VJCOMP); 111836285Sbrian memcpy(dec->nakend+2, &pcomp, 2); 111936285Sbrian dec->nakend += length; 11206059Samurai } 11216059Samurai break; 112228679Sbrian case 6: /* RFC1332 */ 112343545Sbrian if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 112443545Sbrian if (pcomp->slots <= MAX_VJ_STATES 112543545Sbrian && pcomp->slots >= MIN_VJ_STATES) { 112643545Sbrian /* Ok, we can do that */ 112743545Sbrian ipcp->peer_compproto = compproto; 112843545Sbrian ipcp->heis1172 = 0; 112943545Sbrian memcpy(dec->ackend, cp, length); 113043545Sbrian dec->ackend += length; 113143545Sbrian } else { 113243545Sbrian /* Get as close as we can to what he wants */ 113343545Sbrian ipcp->heis1172 = 0; 113443545Sbrian memcpy(dec->nakend, cp, 2); 113543545Sbrian pcomp->slots = pcomp->slots < MIN_VJ_STATES ? 113643545Sbrian MIN_VJ_STATES : MAX_VJ_STATES; 113743545Sbrian memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 113843545Sbrian dec->nakend += length; 113943545Sbrian } 11406059Samurai } else { 114143545Sbrian /* What we really want */ 114236285Sbrian memcpy(dec->nakend, cp, 2); 11436059Samurai pcomp->proto = htons(PROTO_VJCOMP); 114436285Sbrian pcomp->slots = DEF_VJ_STATES; 114543545Sbrian pcomp->compcid = 1; 114636285Sbrian memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 114736285Sbrian dec->nakend += length; 11486059Samurai } 11496059Samurai break; 11506059Samurai default: 115136285Sbrian memcpy(dec->rejend, cp, length); 115236285Sbrian dec->rejend += length; 11536059Samurai break; 11546059Samurai } 11556059Samurai } 11566059Samurai break; 115740561Sbrian 11586059Samurai case MODE_NAK: 115943545Sbrian if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 116043545Sbrian if (pcomp->slots > MAX_VJ_STATES) 116143545Sbrian pcomp->slots = MAX_VJ_STATES; 116243545Sbrian else if (pcomp->slots < MIN_VJ_STATES) 116343545Sbrian pcomp->slots = MIN_VJ_STATES; 116443545Sbrian compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 116543545Sbrian pcomp->compcid; 116643545Sbrian } else 116743545Sbrian compproto = 0; 116836285Sbrian log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 116936285Sbrian tbuff, ipcp->my_compproto, compproto); 117043545Sbrian ipcp->my_compproto = compproto; 11716059Samurai break; 117240561Sbrian 11736059Samurai case MODE_REJ: 117436285Sbrian ipcp->peer_reject |= (1 << type); 11756059Samurai break; 11766059Samurai } 11776059Samurai break; 117840561Sbrian 117928679Sbrian case TY_IPADDRS: /* RFC1172 */ 118038814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 118138814Sbrian memcpy(&dstipaddr.s_addr, cp + 6, 4); 118231962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 118336285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 11846059Samurai 118531034Sbrian switch (mode_type) { 11866059Samurai case MODE_REQ: 118746686Sbrian memcpy(dec->rejend, cp, length); 118846686Sbrian dec->rejend += length; 11896059Samurai break; 119040561Sbrian 11916059Samurai case MODE_NAK: 11926059Samurai case MODE_REJ: 11936059Samurai break; 11946059Samurai } 11956059Samurai break; 119618752Sjkh 119736285Sbrian case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ 119836285Sbrian case TY_SECONDARY_DNS: 119938814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 120036285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 120118752Sjkh 120231034Sbrian switch (mode_type) { 120318752Sjkh case MODE_REQ: 120436285Sbrian if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { 120536285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 120636285Sbrian memcpy(dec->rejend, cp, length); 120736285Sbrian dec->rejend += length; 120836285Sbrian break; 120936285Sbrian } 121081634Sbrian have_ip = ipcp->ns.dns[type == TY_PRIMARY_DNS ? 0 : 1]; 121158044Sbrian 121258044Sbrian if (type == TY_PRIMARY_DNS && ipaddr.s_addr != have_ip.s_addr && 121381634Sbrian ipaddr.s_addr == ipcp->ns.dns[1].s_addr) { 121458044Sbrian /* Swap 'em 'round */ 121581634Sbrian ipcp->ns.dns[0] = ipcp->ns.dns[1]; 121681634Sbrian ipcp->ns.dns[1] = have_ip; 121781634Sbrian have_ip = ipcp->ns.dns[0]; 121836285Sbrian } 121928679Sbrian 122036285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 122118752Sjkh /* 122236285Sbrian * The client has got the DNS stuff wrong (first request) so 122328974Sbrian * we'll tell 'em how it is 122428679Sbrian */ 122536285Sbrian memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ 122636285Sbrian memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); 122736285Sbrian dec->nakend += length; 122836285Sbrian } else { 122936285Sbrian /* 123036285Sbrian * Otherwise they have it right (this time) so we send a ack packet 123136285Sbrian * back confirming it... end of story 123236285Sbrian */ 123336285Sbrian memcpy(dec->ackend, cp, length); 123436285Sbrian dec->ackend += length; 123536285Sbrian } 123618752Sjkh break; 123740561Sbrian 123858044Sbrian case MODE_NAK: 123936285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 124036285Sbrian gotdnsnak = 1; 124181634Sbrian memcpy(&ipcp->ns.dns[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, 124281634Sbrian cp + 2, 4); 124336285Sbrian } 124418752Sjkh break; 124540561Sbrian 124636285Sbrian case MODE_REJ: /* Can't do much, stop asking */ 124736285Sbrian ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); 124818752Sjkh break; 124918752Sjkh } 125018752Sjkh break; 125118752Sjkh 125236285Sbrian case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ 125318752Sjkh case TY_SECONDARY_NBNS: 125438814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 125536285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 125636285Sbrian 125731034Sbrian switch (mode_type) { 125818752Sjkh case MODE_REQ: 125936285Sbrian have_ip.s_addr = 126036285Sbrian ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; 126136285Sbrian 126236285Sbrian if (have_ip.s_addr == INADDR_ANY) { 126336285Sbrian log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); 126436285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 126536285Sbrian memcpy(dec->rejend, cp, length); 126636285Sbrian dec->rejend += length; 126718752Sjkh break; 126836285Sbrian } 126936285Sbrian 127036285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 127136285Sbrian memcpy(dec->nakend, cp, 2); 127236285Sbrian memcpy(dec->nakend+2, &have_ip.s_addr, length); 127336285Sbrian dec->nakend += length; 127436285Sbrian } else { 127536285Sbrian memcpy(dec->ackend, cp, length); 127636285Sbrian dec->ackend += length; 127736285Sbrian } 127818752Sjkh break; 127940561Sbrian 128018752Sjkh case MODE_NAK: 128136285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 128218752Sjkh break; 128340561Sbrian 128418752Sjkh case MODE_REJ: 128536285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 128618752Sjkh break; 128718752Sjkh } 128818752Sjkh break; 128918752Sjkh 12906059Samurai default: 129136285Sbrian if (mode_type != MODE_NOP) { 129236285Sbrian ipcp->my_reject |= (1 << type); 129336285Sbrian memcpy(dec->rejend, cp, length); 129436285Sbrian dec->rejend += length; 129536285Sbrian } 12966059Samurai break; 12976059Samurai } 12986059Samurai plen -= length; 12996059Samurai cp += length; 13006059Samurai } 130136285Sbrian 130258044Sbrian if (gotdnsnak) { 130358044Sbrian if (ipcp->ns.writable) { 130458044Sbrian log_Printf(LogDEBUG, "Updating resolver\n"); 130558044Sbrian if (!ipcp_WriteDNS(ipcp)) { 130658044Sbrian ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); 130758044Sbrian ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); 130858044Sbrian } else 130981634Sbrian bundle_AdjustDNS(fp->bundle); 131058044Sbrian } else { 131158044Sbrian log_Printf(LogDEBUG, "Not updating resolver (readonly)\n"); 131281634Sbrian bundle_AdjustDNS(fp->bundle); 131336285Sbrian } 131458044Sbrian } 131536285Sbrian 131636285Sbrian if (mode_type != MODE_NOP) { 131780476Sbrian if (mode_type == MODE_REQ && !ipcp->peer_req) { 131880476Sbrian if (dec->rejend == dec->rej && dec->nakend == dec->nak) { 131980476Sbrian /* 132080476Sbrian * Pretend the peer has requested an IP. 132180476Sbrian * We do this to ensure that we only send one NAK if the only 132280476Sbrian * reason for the NAK is because the peer isn't sending a 132380476Sbrian * TY_IPADDR REQ. This stops us from repeatedly trying to tell 132480476Sbrian * the peer that we have to have an IP address on their end. 132580476Sbrian */ 132680476Sbrian ipcp->peer_req = 1; 132780476Sbrian } 132876986Sbrian ipaddr.s_addr = INADDR_ANY; 132976986Sbrian ipcp_ValidateReq(ipcp, ipaddr, dec); 133076986Sbrian } 133136285Sbrian if (dec->rejend != dec->rej) { 133236285Sbrian /* rejects are preferred */ 133336285Sbrian dec->ackend = dec->ack; 133436285Sbrian dec->nakend = dec->nak; 133536285Sbrian } else if (dec->nakend != dec->nak) 133636285Sbrian /* then NAKs */ 133736285Sbrian dec->ackend = dec->ack; 133836285Sbrian } 13396059Samurai} 13406059Samurai 134146686Sbrianextern struct mbuf * 134246686Sbrianipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 13436059Samurai{ 134436285Sbrian /* Got PROTO_IPCP from link */ 134554912Sbrian m_settype(bp, MB_IPCPIN); 134636285Sbrian if (bundle_Phase(bundle) == PHASE_NETWORK) 134746686Sbrian fsm_Input(&bundle->ncp.ipcp.fsm, bp); 134836285Sbrian else { 134936285Sbrian if (bundle_Phase(bundle) < PHASE_NETWORK) 135036285Sbrian log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", 135146686Sbrian l->name, bundle_PhaseName(bundle)); 135254912Sbrian m_freem(bp); 135336285Sbrian } 135446686Sbrian return NULL; 13556059Samurai} 135632267Sbrian 135732267Sbrianint 135843313Sbrianipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr) 135943313Sbrian{ 136043313Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 136181634Sbrian struct in_addr myaddr; 136243313Sbrian 136343313Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 136443313Sbrian iplist_reset(&ipcp->cfg.peer_list); 136581634Sbrian ipcp->peer_ip = hisaddr; 136681634Sbrian ncprange_setip4host(&ipcp->cfg.peer_range, hisaddr); 136781634Sbrian ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr); 136843313Sbrian 136981634Sbrian return ipcp_SetIPaddress(ipcp, myaddr, hisaddr); 137043313Sbrian} 137143313Sbrian 137243313Sbrianint 137336285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 137432267Sbrian{ 137581634Sbrian struct in_addr myaddr; 137681634Sbrian struct ncp *ncp = &bundle->ncp; 137781634Sbrian struct ipcp *ipcp = &ncp->ipcp; 137881634Sbrian struct ncpaddr ncpaddr; 137936285Sbrian 138036285Sbrian /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 138136285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 138236285Sbrian iplist_reset(&ipcp->cfg.peer_list); 138332267Sbrian if (strpbrk(hisaddr, ",-")) { 138436285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); 138536285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 138636285Sbrian iplist_setrandpos(&ipcp->cfg.peer_list); 138736285Sbrian ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); 138836285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 138936285Sbrian log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); 139047648Sbrian return 0; 139132267Sbrian } 139281634Sbrian ncprange_setip4host(&ipcp->cfg.peer_range, ipcp->peer_ip); 139332267Sbrian } else { 139436285Sbrian log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); 139532267Sbrian return 0; 139632267Sbrian } 139781634Sbrian } else if (ncprange_aton(&ipcp->cfg.peer_range, ncp, hisaddr) != 0) { 139881634Sbrian if (ncprange_family(&ipcp->cfg.my_range) != AF_INET) { 139981634Sbrian log_Printf(LogWARN, "%s: Not an AF_INET address !\n", hisaddr); 140081634Sbrian return 0; 140181634Sbrian } 140281634Sbrian ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr); 140381634Sbrian ncprange_getip4addr(&ipcp->cfg.peer_range, &ipcp->peer_ip); 140432267Sbrian 140581634Sbrian if (setaddr && !ipcp_SetIPaddress(ipcp, myaddr, ipcp->peer_ip)) 140632267Sbrian return 0; 140732267Sbrian } else 140832267Sbrian return 0; 140932267Sbrian 141081634Sbrian ncpaddr_setip4(&ncpaddr, ipcp->peer_ip); 141181634Sbrian bundle_AdjustFilters(bundle, NULL, &ncpaddr); 141247648Sbrian 141347648Sbrian return 1; /* Ok */ 141432267Sbrian} 141544455Sbrian 141644455Sbrianstruct in_addr 141744455Sbrianaddr2mask(struct in_addr addr) 141844455Sbrian{ 141944455Sbrian u_int32_t haddr = ntohl(addr.s_addr); 142044455Sbrian 142144455Sbrian haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET : 142244455Sbrian IN_CLASSB(haddr) ? IN_CLASSB_NET : 142344455Sbrian IN_CLASSC_NET; 142444455Sbrian addr.s_addr = htonl(haddr); 142544455Sbrian 142644455Sbrian return addr; 142744455Sbrian} 142881634Sbrian 142981634Sbriansize_t 143081634Sbrianipcp_QueueLen(struct ipcp *ipcp) 143181634Sbrian{ 143281634Sbrian struct mqueue *q; 143381634Sbrian size_t result; 143481634Sbrian 143581634Sbrian result = 0; 143681634Sbrian for (q = ipcp->Queue; q < ipcp->Queue + IPCP_QUEUES(ipcp); q++) 143781634Sbrian result += q->len; 143881634Sbrian 143981634Sbrian return result; 144081634Sbrian} 144181634Sbrian 144281634Sbrianint 144381634Sbrianipcp_PushPacket(struct ipcp *ipcp, struct link *l) 144481634Sbrian{ 144581634Sbrian struct bundle *bundle = ipcp->fsm.bundle; 144681634Sbrian struct mqueue *queue; 144781634Sbrian struct mbuf *bp; 144881634Sbrian int m_len; 144981634Sbrian u_int32_t secs = 0; 145081634Sbrian unsigned alivesecs = 0; 145181634Sbrian 145281634Sbrian if (ipcp->fsm.state != ST_OPENED) 145381634Sbrian return 0; 145481634Sbrian 145581634Sbrian /* 145681634Sbrian * If ccp is not open but is required, do nothing. 145781634Sbrian */ 145881634Sbrian if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) { 145981634Sbrian log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name); 146081634Sbrian return 0; 146181634Sbrian } 146281634Sbrian 146381634Sbrian queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1; 146481634Sbrian do { 146581634Sbrian if (queue->top) { 146681634Sbrian bp = m_dequeue(queue); 146781634Sbrian bp = mbuf_Read(bp, &secs, sizeof secs); 146881634Sbrian bp = m_pullup(bp); 146981634Sbrian m_len = m_length(bp); 147081634Sbrian if (!FilterCheck(MBUF_CTOP(bp), AF_INET, &bundle->filter.alive, 147181634Sbrian &alivesecs)) { 147281634Sbrian if (secs == 0) 147381634Sbrian secs = alivesecs; 147481634Sbrian bundle_StartIdleTimer(bundle, secs); 147581634Sbrian } 147681634Sbrian link_PushPacket(l, bp, bundle, 0, PROTO_IP); 147781634Sbrian ipcp_AddOutOctets(ipcp, m_len); 147881634Sbrian return 1; 147981634Sbrian } 148081634Sbrian } while (queue-- != ipcp->Queue); 148181634Sbrian 148281634Sbrian return 0; 148381634Sbrian} 1484