ipcp.c revision 44455
16059Samurai/* 26059Samurai * PPP IP Control Protocol (IPCP) Module 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 196059Samurai * 2044455Sbrian * $Id: ipcp.c,v 1.72 1999/02/26 21:28:11 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 2337160Sbrian * o More RFC1772 backward compatibility 246059Samurai */ 2530715Sbrian#include <sys/param.h> 266059Samurai#include <netinet/in_systm.h> 2729048Sbrian#include <netinet/in.h> 286059Samurai#include <netinet/ip.h> 296059Samurai#include <arpa/inet.h> 306059Samurai#include <sys/socket.h> 3140665Sbrian#include <net/route.h> 3230715Sbrian#include <netdb.h> 3336285Sbrian#include <sys/un.h> 3430715Sbrian 3536285Sbrian#include <fcntl.h> 3636285Sbrian#include <resolv.h> 3732614Sbrian#include <stdlib.h> 3830715Sbrian#include <string.h> 3936285Sbrian#include <sys/errno.h> 4036285Sbrian#include <termios.h> 4130715Sbrian#include <unistd.h> 4230715Sbrian 4339395Sbrian#ifndef NOALIAS 4439395Sbrian#ifdef __OpenBSD__ 4539395Sbrian#include "alias.h" 4639395Sbrian#else 4739395Sbrian#include <alias.h> 4839395Sbrian#endif 4939395Sbrian#endif 5038814Sbrian#include "ua.h" 5137009Sbrian#include "defs.h" 5231343Sbrian#include "command.h" 5330715Sbrian#include "mbuf.h" 5430715Sbrian#include "log.h" 5530715Sbrian#include "timer.h" 5629048Sbrian#include "fsm.h" 5729048Sbrian#include "lcpproto.h" 5829048Sbrian#include "lcp.h" 5931690Sbrian#include "iplist.h" 6036285Sbrian#include "throughput.h" 6136285Sbrian#include "slcompress.h" 6238557Sbrian#include "lqr.h" 6338557Sbrian#include "hdlc.h" 6429048Sbrian#include "ipcp.h" 6536285Sbrian#include "filter.h" 6636285Sbrian#include "descriptor.h" 6730715Sbrian#include "vjcomp.h" 6836285Sbrian#include "async.h" 6936285Sbrian#include "ccp.h" 7036285Sbrian#include "link.h" 7136285Sbrian#include "physical.h" 7236285Sbrian#include "mp.h" 7343313Sbrian#ifndef NORADIUS 7443313Sbrian#include "radius.h" 7543313Sbrian#endif 7636285Sbrian#include "bundle.h" 7736285Sbrian#include "id.h" 7836285Sbrian#include "arp.h" 7936285Sbrian#include "systems.h" 8036285Sbrian#include "prompt.h" 8131690Sbrian#include "route.h" 8240561Sbrian#include "iface.h" 836059Samurai 8436285Sbrian#undef REJECTED 8536285Sbrian#define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) 8636285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t') 8736285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.') 886059Samurai 8936285Sbrianstruct compreq { 9036285Sbrian u_short proto; 9136285Sbrian u_char slots; 9236285Sbrian u_char compcid; 9336285Sbrian}; 946059Samurai 9536285Sbrianstatic int IpcpLayerUp(struct fsm *); 9636285Sbrianstatic void IpcpLayerDown(struct fsm *); 9726516Sbrianstatic void IpcpLayerStart(struct fsm *); 9826516Sbrianstatic void IpcpLayerFinish(struct fsm *); 9944305Sbrianstatic void IpcpInitRestartCounter(struct fsm *, int); 10036285Sbrianstatic void IpcpSendConfigReq(struct fsm *); 10136285Sbrianstatic void IpcpSentTerminateReq(struct fsm *); 10236285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char); 10336285Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, int, int, 10436285Sbrian struct fsm_decode *); 1056059Samurai 10636285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = { 1076059Samurai IpcpLayerUp, 1086059Samurai IpcpLayerDown, 1096059Samurai IpcpLayerStart, 1106059Samurai IpcpLayerFinish, 1116059Samurai IpcpInitRestartCounter, 1126059Samurai IpcpSendConfigReq, 11336285Sbrian IpcpSentTerminateReq, 1146059Samurai IpcpSendTerminateAck, 1156059Samurai IpcpDecodeConfig, 11636285Sbrian fsm_NullRecvResetReq, 11736285Sbrian fsm_NullRecvResetAck 1186059Samurai}; 1196059Samurai 12031343Sbrianstatic const char *cftypes[] = { 12131171Sbrian /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 12231171Sbrian "???", 12331171Sbrian "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ 12431171Sbrian "COMPPROTO", /* 2: IP-Compression-Protocol */ 12531171Sbrian "IPADDR", /* 3: IP-Address */ 1266059Samurai}; 1276059Samurai 12831962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 12931171Sbrian 13031343Sbrianstatic const char *cftypes128[] = { 13131171Sbrian /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 13231171Sbrian "???", 13331171Sbrian "PRIDNS", /* 129: Primary DNS Server Address */ 13431171Sbrian "PRINBNS", /* 130: Primary NBNS Server Address */ 13531171Sbrian "SECDNS", /* 131: Secondary DNS Server Address */ 13631171Sbrian "SECNBNS", /* 132: Secondary NBNS Server Address */ 13731171Sbrian}; 13831171Sbrian 13931962Sbrian#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) 14031171Sbrian 14131272Sbrianvoid 14236285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n) 1436059Samurai{ 14436285Sbrian throughput_addin(&ipcp->throughput, n); 1456059Samurai} 1466059Samurai 14731272Sbrianvoid 14836285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n) 1496059Samurai{ 15036285Sbrian throughput_addout(&ipcp->throughput, n); 1516059Samurai} 1526059Samurai 15336285Sbrianstatic void 15436285Sbriangetdns(struct ipcp *ipcp, struct in_addr addr[2]) 1556059Samurai{ 15636285Sbrian FILE *fp; 1576059Samurai 15836285Sbrian addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 15936285Sbrian if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 16036285Sbrian char buf[LINE_LEN], *cp, *end; 16136285Sbrian int n; 16236285Sbrian 16336285Sbrian n = 0; 16436285Sbrian buf[sizeof buf - 1] = '\0'; 16536285Sbrian while (fgets(buf, sizeof buf - 1, fp)) { 16636285Sbrian if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) { 16736285Sbrian for (cp = buf + 11; issep(*cp); cp++) 16836285Sbrian ; 16936285Sbrian for (end = cp; isip(*end); end++) 17036285Sbrian ; 17136285Sbrian *end = '\0'; 17236285Sbrian if (inet_aton(cp, addr+n) && ++n == 2) 17336285Sbrian break; 17436285Sbrian } 17536285Sbrian } 17636285Sbrian if (n == 1) 17736285Sbrian addr[1] = addr[0]; 17836285Sbrian fclose(fp); 17932614Sbrian } 18036285Sbrian} 18129048Sbrian 18236285Sbrianstatic int 18336285Sbriansetdns(struct ipcp *ipcp, struct in_addr addr[2]) 18436285Sbrian{ 18536285Sbrian FILE *fp; 18636285Sbrian char wbuf[LINE_LEN + 54]; 18736285Sbrian int wlen; 18826516Sbrian 18936285Sbrian if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) { 19036285Sbrian struct in_addr old[2]; 19131272Sbrian 19236285Sbrian getdns(ipcp, old); 19336285Sbrian if (addr[0].s_addr == INADDR_ANY) 19436285Sbrian addr[0] = old[0]; 19536285Sbrian if (addr[1].s_addr == INADDR_ANY) 19636285Sbrian addr[1] = old[1]; 19736285Sbrian } 19836285Sbrian 19936285Sbrian if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) { 20036285Sbrian log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n", 20136285Sbrian _PATH_RESCONF); 20236285Sbrian return 0; 20336285Sbrian } 20436285Sbrian 20536285Sbrian wlen = 0; 20636285Sbrian if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 20736285Sbrian char buf[LINE_LEN]; 20836285Sbrian int len; 20936285Sbrian 21036285Sbrian buf[sizeof buf - 1] = '\0'; 21136285Sbrian while (fgets(buf, sizeof buf - 1, fp)) { 21236285Sbrian if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) { 21336285Sbrian len = strlen(buf); 21436285Sbrian if (len > sizeof wbuf - wlen) { 21536285Sbrian log_Printf(LogWARN, "%s: Can only cope with max file size %d\n", 21636285Sbrian _PATH_RESCONF, LINE_LEN); 21736285Sbrian fclose(fp); 21836285Sbrian return 0; 21936285Sbrian } 22036285Sbrian memcpy(wbuf + wlen, buf, len); 22136285Sbrian wlen += len; 22236285Sbrian } 22336285Sbrian } 22436285Sbrian fclose(fp); 22536285Sbrian } 22636285Sbrian 22736285Sbrian if (addr[0].s_addr != INADDR_ANY) { 22836285Sbrian snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 22936285Sbrian inet_ntoa(addr[0])); 23036285Sbrian log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11); 23136285Sbrian wlen += strlen(wbuf + wlen); 23236285Sbrian } 23336285Sbrian 23436285Sbrian if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) { 23536285Sbrian snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 23636285Sbrian inet_ntoa(addr[1])); 23736285Sbrian log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11); 23836285Sbrian wlen += strlen(wbuf + wlen); 23936285Sbrian } 24036285Sbrian 24136285Sbrian if (wlen) { 24236285Sbrian int fd; 24336285Sbrian 24436285Sbrian if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) { 24536285Sbrian if (write(fd, wbuf, wlen) != wlen) { 24636285Sbrian log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno)); 24736285Sbrian close(fd); 24836285Sbrian return 0; 24936285Sbrian } 25036285Sbrian if (ftruncate(fd, wlen) == -1) { 25136285Sbrian log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno)); 25236285Sbrian close(fd); 25336285Sbrian return 0; 25436285Sbrian } 25536285Sbrian close(fd); 25636285Sbrian } else { 25736285Sbrian log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno)); 25836285Sbrian return 0; 25936285Sbrian } 26036285Sbrian } 26136285Sbrian 26236285Sbrian return 1; 2636059Samurai} 2646059Samurai 26536285Sbrianint 26636285Sbrianipcp_Show(struct cmdargs const *arg) 2676059Samurai{ 26836285Sbrian struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 2696059Samurai 27036285Sbrian prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, 27136285Sbrian State2Nam(ipcp->fsm.state)); 27236285Sbrian if (ipcp->fsm.state == ST_OPENED) { 27336285Sbrian prompt_Printf(arg->prompt, " His side: %s, %s\n", 27436285Sbrian inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); 27536285Sbrian prompt_Printf(arg->prompt, " My side: %s, %s\n", 27636285Sbrian inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); 2776059Samurai } 27836285Sbrian 27936285Sbrian if (ipcp->route) { 28036285Sbrian prompt_Printf(arg->prompt, "\n"); 28143313Sbrian route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1); 28236285Sbrian } 28336285Sbrian 28436285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 28544305Sbrian prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 28644305Sbrian " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout, 28744305Sbrian ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s", 28844305Sbrian ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s"); 28936285Sbrian prompt_Printf(arg->prompt, " My Address: %s/%d", 29036285Sbrian inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width); 29144455Sbrian prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask)); 29236285Sbrian if (ipcp->cfg.HaveTriggerAddress) 29344455Sbrian prompt_Printf(arg->prompt, " Trigger address: %s\n", 29436285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 29544455Sbrian 29644455Sbrian prompt_Printf(arg->prompt, " VJ compression: %s (%d slots %s slot " 29736285Sbrian "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), 29836285Sbrian ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); 29936285Sbrian 30036285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) 30136285Sbrian prompt_Printf(arg->prompt, " His Address: %s\n", 30236285Sbrian ipcp->cfg.peer_list.src); 30336285Sbrian else 30436285Sbrian prompt_Printf(arg->prompt, " His Address: %s/%d\n", 30536285Sbrian inet_ntoa(ipcp->cfg.peer_range.ipaddr), 30636285Sbrian ipcp->cfg.peer_range.width); 30736285Sbrian 30836285Sbrian prompt_Printf(arg->prompt, " DNS: %s, ", 30936285Sbrian inet_ntoa(ipcp->cfg.ns.dns[0])); 31036285Sbrian prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]), 31136285Sbrian command_ShowNegval(ipcp->cfg.ns.dns_neg)); 31236285Sbrian prompt_Printf(arg->prompt, " NetBIOS NS: %s, ", 31336285Sbrian inet_ntoa(ipcp->cfg.ns.nbns[0])); 31436285Sbrian prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1])); 31536285Sbrian 31636285Sbrian prompt_Printf(arg->prompt, "\n"); 31736285Sbrian throughput_disp(&ipcp->throughput, arg->prompt); 31836285Sbrian 31936285Sbrian return 0; 3206059Samurai} 3216059Samurai 32232614Sbrianint 32336285Sbrianipcp_vjset(struct cmdargs const *arg) 32432614Sbrian{ 32536285Sbrian if (arg->argc != arg->argn+2) 32632614Sbrian return -1; 32736285Sbrian if (!strcasecmp(arg->argv[arg->argn], "slots")) { 32832614Sbrian int slots; 32932614Sbrian 33036285Sbrian slots = atoi(arg->argv[arg->argn+1]); 33132614Sbrian if (slots < 4 || slots > 16) 33232614Sbrian return 1; 33336285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slots = slots; 33432614Sbrian return 0; 33536285Sbrian } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { 33636285Sbrian if (!strcasecmp(arg->argv[arg->argn+1], "on")) 33736285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; 33836285Sbrian else if (!strcasecmp(arg->argv[arg->argn+1], "off")) 33936285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; 34032614Sbrian else 34132614Sbrian return 2; 34232614Sbrian return 0; 34332614Sbrian } 34432614Sbrian return -1; 34532614Sbrian} 34632614Sbrian 34736285Sbrianvoid 34836285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, 34936285Sbrian const struct fsm_parent *parent) 35032614Sbrian{ 35136285Sbrian struct hostent *hp; 35236285Sbrian char name[MAXHOSTNAMELEN]; 35336285Sbrian static const char *timer_names[] = 35436285Sbrian {"IPCP restart", "IPCP openmode", "IPCP stopped"}; 35536285Sbrian 35644305Sbrian fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP, 35736285Sbrian bundle, l, parent, &ipcp_Callbacks, timer_names); 35836285Sbrian 35936285Sbrian ipcp->route = NULL; 36036285Sbrian ipcp->cfg.vj.slots = DEF_VJ_STATES; 36136285Sbrian ipcp->cfg.vj.slotcomp = 1; 36236285Sbrian memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 36336285Sbrian if (gethostname(name, sizeof name) == 0) { 36436285Sbrian hp = gethostbyname(name); 36540561Sbrian if (hp && hp->h_addrtype == AF_INET) 36636285Sbrian memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); 36732614Sbrian } 36836285Sbrian ipcp->cfg.netmask.s_addr = INADDR_ANY; 36936285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 37036285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, ""); 37136285Sbrian ipcp->cfg.HaveTriggerAddress = 0; 37236285Sbrian 37336285Sbrian ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY; 37436285Sbrian ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY; 37536285Sbrian ipcp->cfg.ns.dns_neg = 0; 37636285Sbrian ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; 37736285Sbrian ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; 37836285Sbrian 37944305Sbrian ipcp->cfg.fsm.timeout = DEF_FSMRETRY; 38044305Sbrian ipcp->cfg.fsm.maxreq = DEF_FSMTRIES; 38144305Sbrian ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES; 38236285Sbrian ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; 38336285Sbrian 38436285Sbrian memset(&ipcp->vj, '\0', sizeof ipcp->vj); 38536285Sbrian 38636285Sbrian throughput_init(&ipcp->throughput); 38738557Sbrian memset(ipcp->Queue, '\0', sizeof ipcp->Queue); 38843313Sbrian ipcp_Setup(ipcp, INADDR_NONE); 38932614Sbrian} 39032614Sbrian 3916059Samuraivoid 39236285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l) 3936059Samurai{ 39436285Sbrian ipcp->fsm.link = l; 39536285Sbrian} 39636285Sbrian 39736285Sbrianvoid 39843313Sbrianipcp_Setup(struct ipcp *ipcp, u_int32_t mask) 39936285Sbrian{ 40040561Sbrian struct iface *iface = ipcp->fsm.bundle->iface; 40140561Sbrian int pos, n; 40236285Sbrian 40336285Sbrian ipcp->fsm.open_mode = 0; 40443313Sbrian ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask; 40536285Sbrian 40636285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 40740561Sbrian /* Try to give the peer a previously configured IP address */ 40840561Sbrian for (n = 0; n < iface->in_addrs; n++) { 40940561Sbrian pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd); 41040561Sbrian if (pos != -1) { 41140561Sbrian ipcp->cfg.peer_range.ipaddr = 41240561Sbrian iplist_setcurpos(&ipcp->cfg.peer_list, pos); 41340561Sbrian break; 41440561Sbrian } 41540561Sbrian } 41640561Sbrian if (n == iface->in_addrs) 41740561Sbrian /* Ok, so none of 'em fit.... pick a random one */ 41836285Sbrian ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); 41940561Sbrian 42036285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 42136285Sbrian ipcp->cfg.peer_range.width = 32; 4226059Samurai } 4239440Samurai 42436285Sbrian ipcp->heis1172 = 0; 42536285Sbrian 42636285Sbrian ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; 42736285Sbrian ipcp->peer_compproto = 0; 42836285Sbrian 42936285Sbrian if (ipcp->cfg.HaveTriggerAddress) { 43036285Sbrian /* 43136285Sbrian * Some implementations of PPP require that we send a 43236285Sbrian * *special* value as our address, even though the rfc specifies 43336285Sbrian * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 43436285Sbrian */ 43536285Sbrian ipcp->my_ip = ipcp->cfg.TriggerAddress; 43636285Sbrian log_Printf(LogIPCP, "Using trigger address %s\n", 43736285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 43840561Sbrian } else { 43936285Sbrian /* 44040561Sbrian * Otherwise, if we've used an IP number before and it's still within 44140561Sbrian * the network specified on the ``set ifaddr'' line, we really 44240561Sbrian * want to keep that IP number so that we can keep any existing 44340561Sbrian * connections that are bound to that IP (assuming we're not 44440561Sbrian * ``iface-alias''ing). 44536285Sbrian */ 44640561Sbrian for (n = 0; n < iface->in_addrs; n++) 44740561Sbrian if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) == 44840561Sbrian (ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) { 44940561Sbrian ipcp->my_ip = iface->in_addr[n].ifa; 45040561Sbrian break; 45140561Sbrian } 45240561Sbrian if (n == iface->in_addrs) 45340561Sbrian ipcp->my_ip = ipcp->cfg.my_range.ipaddr; 45440561Sbrian } 45536285Sbrian 45643313Sbrian if (IsEnabled(ipcp->cfg.vj.neg) 45743313Sbrian#ifndef NORADIUS 45843313Sbrian || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj) 45943313Sbrian#endif 46043313Sbrian ) 46136285Sbrian ipcp->my_compproto = (PROTO_VJCOMP << 16) + 46236285Sbrian ((ipcp->cfg.vj.slots - 1) << 8) + 46336285Sbrian ipcp->cfg.vj.slotcomp; 46436285Sbrian else 46536285Sbrian ipcp->my_compproto = 0; 46636285Sbrian sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); 46736285Sbrian 46836285Sbrian ipcp->peer_reject = 0; 46936285Sbrian ipcp->my_reject = 0; 47036285Sbrian} 47136285Sbrian 47236285Sbrianstatic int 47340665Sbrianipcp_doproxyall(struct bundle *bundle, 47440665Sbrian int (*proxyfun)(struct bundle *, struct in_addr, int), int s) 47540665Sbrian{ 47640665Sbrian int n, ret; 47740665Sbrian struct sticky_route *rp; 47840665Sbrian struct in_addr addr; 47940665Sbrian struct ipcp *ipcp; 48040665Sbrian 48140665Sbrian ipcp = &bundle->ncp.ipcp; 48240665Sbrian for (rp = ipcp->route; rp != NULL; rp = rp->next) { 48344455Sbrian if (rp->mask.s_addr == INADDR_BROADCAST) 48440665Sbrian continue; 48544455Sbrian n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1; 48640665Sbrian if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) { 48740665Sbrian addr = rp->dst; 48840665Sbrian while (n--) { 48940665Sbrian addr.s_addr = htonl(ntohl(addr.s_addr) + 1); 49040665Sbrian log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr)); 49140665Sbrian ret = (*proxyfun)(bundle, addr, s); 49240665Sbrian if (!ret) 49340665Sbrian return ret; 49440665Sbrian } 49540665Sbrian } 49640665Sbrian } 49740665Sbrian 49840665Sbrian return 0; 49940665Sbrian} 50040665Sbrian 50140665Sbrianstatic int 50236285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, 50336285Sbrian struct in_addr hisaddr, int silent) 50436285Sbrian{ 50540665Sbrian static struct in_addr none = { INADDR_ANY }; 50640561Sbrian struct in_addr mask, oaddr; 50736285Sbrian 50844455Sbrian mask = addr2mask(myaddr); 50936285Sbrian 51043313Sbrian if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY && 51144455Sbrian (bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr) 51244455Sbrian mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr; 51336285Sbrian 51440561Sbrian oaddr.s_addr = bundle->iface->in_addrs ? 51540561Sbrian bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY; 51640561Sbrian if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr, 51740561Sbrian IFACE_ADD_FIRST|IFACE_FORCE_ADD)) 51840561Sbrian return -1; 51936285Sbrian 52040561Sbrian if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1 52140561Sbrian && myaddr.s_addr != oaddr.s_addr) 52240561Sbrian /* Nuke the old one */ 52340561Sbrian iface_inDelete(bundle->iface, oaddr); 52436285Sbrian 52540665Sbrian if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0) 52640665Sbrian bundle_SetRoute(bundle, RTM_CHANGE, hisaddr, myaddr, none, 0, 0); 52740665Sbrian 52836285Sbrian if (Enabled(bundle, OPT_SROUTES)) 52936285Sbrian route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); 53036285Sbrian 53143313Sbrian#ifndef NORADIUS 53243313Sbrian if (bundle->radius.valid) 53343313Sbrian route_Change(bundle, bundle->radius.routes, myaddr, hisaddr); 53443313Sbrian#endif 53543313Sbrian 53640665Sbrian if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) { 53740561Sbrian int s = ID0socket(AF_INET, SOCK_DGRAM, 0); 53840561Sbrian if (s < 0) 53940561Sbrian log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n", 54040561Sbrian strerror(errno)); 54140561Sbrian else { 54240665Sbrian if (Enabled(bundle, OPT_PROXYALL)) 54340665Sbrian ipcp_doproxyall(bundle, arp_SetProxy, s); 54440665Sbrian else if (Enabled(bundle, OPT_PROXY)) 54540665Sbrian arp_SetProxy(bundle, hisaddr, s); 54640561Sbrian close(s); 54740561Sbrian } 54840561Sbrian } 54936285Sbrian 55040561Sbrian return 0; 5516059Samurai} 5526059Samurai 55336285Sbrianstatic struct in_addr 55440561SbrianChooseHisAddr(struct bundle *bundle, struct in_addr gw) 55536285Sbrian{ 55636285Sbrian struct in_addr try; 55737210Sbrian u_long f; 55836285Sbrian 55936285Sbrian for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { 56036285Sbrian try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); 56137210Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n", 56236285Sbrian f, inet_ntoa(try)); 56336285Sbrian if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { 56436285Sbrian log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); 56536285Sbrian break; 56636285Sbrian } 56736285Sbrian } 56836285Sbrian 56936285Sbrian if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { 57036285Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 57136285Sbrian try.s_addr = INADDR_ANY; 57236285Sbrian } 57336285Sbrian 57436285Sbrian return try; 57536285Sbrian} 57636285Sbrian 5776059Samuraistatic void 57844305SbrianIpcpInitRestartCounter(struct fsm *fp, int what) 5796059Samurai{ 58036285Sbrian /* Set fsm timer load */ 58136285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 58236285Sbrian 58344305Sbrian fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS; 58444305Sbrian switch (what) { 58544305Sbrian case FSM_REQ_TIMER: 58644305Sbrian fp->restart = ipcp->cfg.fsm.maxreq; 58744305Sbrian break; 58844305Sbrian case FSM_TRM_TIMER: 58944305Sbrian fp->restart = ipcp->cfg.fsm.maxtrm; 59044305Sbrian break; 59144305Sbrian default: 59244305Sbrian fp->restart = 1; 59344305Sbrian break; 59444305Sbrian } 5956059Samurai} 5966059Samurai 5976059Samuraistatic void 59836285SbrianIpcpSendConfigReq(struct fsm *fp) 5996059Samurai{ 60036285Sbrian /* Send config REQ please */ 60136285Sbrian struct physical *p = link2physical(fp->link); 60236285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 60336285Sbrian u_char buff[24]; 60436285Sbrian struct lcp_opt *o; 6056059Samurai 60636285Sbrian o = (struct lcp_opt *)buff; 60736285Sbrian 60836285Sbrian if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 60938814Sbrian memcpy(o->data, &ipcp->my_ip.s_addr, 4); 61036285Sbrian INC_LCP_OPT(TY_IPADDR, 6, o); 61131514Sbrian } 61231514Sbrian 61336285Sbrian if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 61436285Sbrian if (ipcp->heis1172) { 61538814Sbrian u_int16_t proto = PROTO_VJCOMP; 61638814Sbrian 61738814Sbrian ua_htons(&proto, o->data); 61836285Sbrian INC_LCP_OPT(TY_COMPPROTO, 4, o); 61931514Sbrian } else { 62043545Sbrian struct compreq req; 62143545Sbrian 62243545Sbrian req.proto = htons(ipcp->my_compproto >> 16); 62343545Sbrian req.slots = (ipcp->my_compproto >> 8) & 255; 62443545Sbrian req.compcid = ipcp->my_compproto & 1; 62543545Sbrian memcpy(o->data, &req, 4); 62636285Sbrian INC_LCP_OPT(TY_COMPPROTO, 6, o); 62731514Sbrian } 6286059Samurai } 62936285Sbrian 63036285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg) && 63136285Sbrian !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && 63236285Sbrian !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { 63336285Sbrian struct in_addr dns[2]; 63436285Sbrian getdns(ipcp, dns); 63538814Sbrian memcpy(o->data, &dns[0].s_addr, 4); 63636285Sbrian INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); 63738814Sbrian memcpy(o->data, &dns[1].s_addr, 4); 63836285Sbrian INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); 63936285Sbrian } 64036285Sbrian 64136285Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff); 6426059Samurai} 6436059Samurai 6446059Samuraistatic void 64544305SbrianIpcpSentTerminateReq(struct fsm *fp) 6466059Samurai{ 64736285Sbrian /* Term REQ just sent by FSM */ 6486059Samurai} 6496059Samurai 6506059Samuraistatic void 65136285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id) 6526059Samurai{ 65336285Sbrian /* Send Term ACK please */ 65436285Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0); 6556059Samurai} 6566059Samurai 6576059Samuraistatic void 65837160SbrianIpcpLayerStart(struct fsm *fp) 6596059Samurai{ 66036285Sbrian /* We're about to start up ! */ 66137160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 66237160Sbrian 66337210Sbrian log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name); 66437160Sbrian throughput_start(&ipcp->throughput, "IPCP throughput", 66537160Sbrian Enabled(fp->bundle, OPT_THROUGHPUT)); 66644305Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 6676059Samurai} 6686059Samurai 6696059Samuraistatic void 67036285SbrianIpcpLayerFinish(struct fsm *fp) 6716059Samurai{ 67236285Sbrian /* We're now down */ 67337160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 67437160Sbrian 67537210Sbrian log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name); 67637160Sbrian throughput_stop(&ipcp->throughput); 67737160Sbrian throughput_log(&ipcp->throughput, LogIPCP, NULL); 6786059Samurai} 6796059Samurai 68036285Sbrianvoid 68136285Sbrianipcp_CleanInterface(struct ipcp *ipcp) 6826059Samurai{ 68340561Sbrian struct iface *iface = ipcp->fsm.bundle->iface; 68436285Sbrian 68536285Sbrian route_Clean(ipcp->fsm.bundle, ipcp->route); 68636285Sbrian 68740665Sbrian if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) || 68840665Sbrian Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) { 68940561Sbrian int s = ID0socket(AF_INET, SOCK_DGRAM, 0); 69040561Sbrian if (s < 0) 69140561Sbrian log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", 69240561Sbrian strerror(errno)); 69340561Sbrian else { 69440665Sbrian if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL)) 69540665Sbrian ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s); 69640665Sbrian else if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) 69740665Sbrian arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s); 69840561Sbrian close(s); 69940561Sbrian } 70036285Sbrian } 70136285Sbrian 70240561Sbrian iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL); 7036059Samurai} 7046059Samurai 7056059Samuraistatic void 70636285SbrianIpcpLayerDown(struct fsm *fp) 7076059Samurai{ 70836285Sbrian /* About to come down */ 70936285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 71036285Sbrian const char *s; 7116059Samurai 71240561Sbrian if (ipcp->fsm.bundle->iface->in_addrs) 71340561Sbrian s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa); 71440561Sbrian else 71540561Sbrian s = "Interface configuration error !"; 71637210Sbrian log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s); 71730187Sbrian 71836285Sbrian /* 71936285Sbrian * XXX this stuff should really live in the FSM. Our config should 72036285Sbrian * associate executable sections in files with events. 72136285Sbrian */ 72237008Sbrian if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) { 72336285Sbrian if (bundle_GetLabel(fp->bundle)) { 72436285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 72537008Sbrian LINKDOWNFILE, NULL, NULL) < 0) 72637008Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 72736285Sbrian } else 72837008Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 72936285Sbrian } 73030187Sbrian 73143313Sbrian ipcp_Setup(ipcp, INADDR_NONE); 73236285Sbrian} 73336285Sbrian 73436285Sbrianint 73536285Sbrianipcp_InterfaceUp(struct ipcp *ipcp) 73636285Sbrian{ 73736285Sbrian if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { 73837019Sbrian log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n"); 73936285Sbrian return 0; 74025630Sbrian } 74136285Sbrian 74231343Sbrian#ifndef NOALIAS 74337191Sbrian if (ipcp->fsm.bundle->AliasEnabled) 74437191Sbrian PacketAliasSetAddress(ipcp->my_ip); 74531343Sbrian#endif 74636285Sbrian 74736285Sbrian return 1; 7486059Samurai} 7496059Samurai 75036285Sbrianstatic int 75136285SbrianIpcpLayerUp(struct fsm *fp) 7526059Samurai{ 75336285Sbrian /* We're now up */ 75436285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 75540561Sbrian char tbuff[16]; 7566059Samurai 75737210Sbrian log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name); 75840561Sbrian snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip)); 75940561Sbrian log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n", 76040561Sbrian tbuff, inet_ntoa(ipcp->peer_ip)); 76136285Sbrian 76236285Sbrian if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 76336285Sbrian sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); 76436285Sbrian 76536285Sbrian if (!ipcp_InterfaceUp(ipcp)) 76636285Sbrian return 0; 76736285Sbrian 76836285Sbrian /* 76936285Sbrian * XXX this stuff should really live in the FSM. Our config should 77036285Sbrian * associate executable sections in files with events. 77136285Sbrian */ 77240561Sbrian if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 77336285Sbrian if (bundle_GetLabel(fp->bundle)) { 77436285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 77537008Sbrian LINKUPFILE, NULL, NULL) < 0) 77637008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 77736285Sbrian } else 77837008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 77936285Sbrian } 78036285Sbrian 78144305Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3; 78236314Sbrian log_DisplayPrompts(); 78344305Sbrian 78436285Sbrian return 1; 7856059Samurai} 7866059Samurai 7876059Samuraistatic int 78840561SbrianAcceptableAddr(const struct in_range *prange, struct in_addr ipaddr) 7896059Samurai{ 79036285Sbrian /* Is the given IP in the given range ? */ 79125661Sbrian return (prange->ipaddr.s_addr & prange->mask.s_addr) == 79228679Sbrian (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 7936059Samurai} 7946059Samurai 7956059Samuraistatic void 79636285SbrianIpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type, 79736285Sbrian struct fsm_decode *dec) 7986059Samurai{ 79936285Sbrian /* Deal with incoming PROTO_IPCP */ 80040561Sbrian struct iface *iface = fp->bundle->iface; 80136285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 80240561Sbrian int type, length, gotdns, gotdnsnak, n; 80336285Sbrian u_int32_t compproto; 8046059Samurai struct compreq *pcomp; 80536285Sbrian struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; 80636285Sbrian char tbuff[100], tbuff2[100]; 8076059Samurai 80836285Sbrian gotdns = 0; 80936285Sbrian gotdnsnak = 0; 81036285Sbrian dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; 8116059Samurai 8126059Samurai while (plen >= sizeof(struct fsmconfig)) { 8136059Samurai type = *cp; 8146059Samurai length = cp[1]; 81536285Sbrian 81636285Sbrian if (length == 0) { 81736285Sbrian log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); 81836285Sbrian break; 81936285Sbrian } 82036285Sbrian 82131171Sbrian if (type < NCFTYPES) 82231962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); 82331171Sbrian else if (type > 128 && type < 128 + NCFTYPES128) 82431962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); 8256059Samurai else 82631962Sbrian snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); 8276059Samurai 8286059Samurai switch (type) { 8296059Samurai case TY_IPADDR: /* RFC1332 */ 83038814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 83136285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 8326059Samurai 83331034Sbrian switch (mode_type) { 8346059Samurai case MODE_REQ: 83536285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 83631850Sbrian if (ipaddr.s_addr == INADDR_ANY || 83736285Sbrian iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || 83836285Sbrian ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, 83936285Sbrian ipaddr, 1)) { 84036285Sbrian log_Printf(LogIPCP, "%s: Address invalid or already in use\n", 84131690Sbrian inet_ntoa(ipaddr)); 84240561Sbrian /* 84340561Sbrian * If we've already had a valid address configured for the peer, 84440561Sbrian * try NAKing with that so that we don't have to upset things 84540561Sbrian * too much. 84640561Sbrian */ 84740561Sbrian for (n = 0; n < iface->in_addrs; n++) 84840561Sbrian if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd) 84940561Sbrian >=0) { 85040561Sbrian ipcp->peer_ip = iface->in_addr[n].brd; 85140561Sbrian break; 85240561Sbrian } 85340561Sbrian 85440561Sbrian if (n == iface->in_addrs) 85536285Sbrian /* Just pick an IP number from our list */ 85636285Sbrian ipcp->peer_ip = ChooseHisAddr 85736285Sbrian (fp->bundle, ipcp->cfg.my_range.ipaddr); 85836285Sbrian 85936285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 86036285Sbrian memcpy(dec->rejend, cp, length); 86136285Sbrian dec->rejend += length; 86231690Sbrian } else { 86336285Sbrian memcpy(dec->nakend, cp, 2); 86440561Sbrian memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2); 86536285Sbrian dec->nakend += length; 86631690Sbrian } 86731690Sbrian break; 86831690Sbrian } 86936285Sbrian } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { 87028679Sbrian /* 87136285Sbrian * If destination address is not acceptable, NAK with what we 87228679Sbrian * want to use. 87328679Sbrian */ 87436285Sbrian memcpy(dec->nakend, cp, 2); 87540561Sbrian for (n = 0; n < iface->in_addrs; n++) 87640561Sbrian if ((iface->in_addr[n].brd.s_addr & 87740561Sbrian ipcp->cfg.peer_range.mask.s_addr) 87840561Sbrian == (ipcp->cfg.peer_range.ipaddr.s_addr & 87940561Sbrian ipcp->cfg.peer_range.mask.s_addr)) { 88040561Sbrian /* We prefer the already-configured address */ 88140561Sbrian memcpy(dec->nakend + 2, &iface->in_addr[n].brd.s_addr, 88240561Sbrian length - 2); 88340561Sbrian break; 88440561Sbrian } 88540561Sbrian 88640561Sbrian if (n == iface->in_addrs) 88740561Sbrian memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2); 88840561Sbrian 88936285Sbrian dec->nakend += length; 89028679Sbrian break; 8916059Samurai } 89236285Sbrian ipcp->peer_ip = ipaddr; 89336285Sbrian memcpy(dec->ackend, cp, length); 89436285Sbrian dec->ackend += length; 8956059Samurai break; 89640561Sbrian 8976059Samurai case MODE_NAK: 89836285Sbrian if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { 89931690Sbrian /* Use address suggested by peer */ 90031962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 90136285Sbrian inet_ntoa(ipcp->my_ip)); 90236285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 90336285Sbrian ipcp->my_ip = ipaddr; 90431690Sbrian } else { 90536285Sbrian log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, 90636285Sbrian "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 90736285Sbrian fsm_Close(&ipcp->fsm); 9086059Samurai } 9096059Samurai break; 91040561Sbrian 9116059Samurai case MODE_REJ: 91236285Sbrian ipcp->peer_reject |= (1 << type); 9136059Samurai break; 9146059Samurai } 9156059Samurai break; 91640561Sbrian 9176059Samurai case TY_COMPPROTO: 91843545Sbrian pcomp = (struct compreq *)(cp + 2); 91943545Sbrian compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 92043545Sbrian pcomp->compcid; 92136285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 9226059Samurai 92331034Sbrian switch (mode_type) { 9246059Samurai case MODE_REQ: 92536285Sbrian if (!IsAccepted(ipcp->cfg.vj.neg)) { 92636285Sbrian memcpy(dec->rejend, cp, length); 92736285Sbrian dec->rejend += length; 9286059Samurai } else { 9296059Samurai switch (length) { 93028679Sbrian case 4: /* RFC1172 */ 9316059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 93243545Sbrian log_Printf(LogWARN, "Peer is speaking RFC1172 compression " 93343545Sbrian "protocol !\n"); 93436285Sbrian ipcp->heis1172 = 1; 93536285Sbrian ipcp->peer_compproto = compproto; 93636285Sbrian memcpy(dec->ackend, cp, length); 93736285Sbrian dec->ackend += length; 9386059Samurai } else { 93936285Sbrian memcpy(dec->nakend, cp, 2); 9406059Samurai pcomp->proto = htons(PROTO_VJCOMP); 94136285Sbrian memcpy(dec->nakend+2, &pcomp, 2); 94236285Sbrian dec->nakend += length; 9436059Samurai } 9446059Samurai break; 94528679Sbrian case 6: /* RFC1332 */ 94643545Sbrian if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 94743545Sbrian if (pcomp->slots <= MAX_VJ_STATES 94843545Sbrian && pcomp->slots >= MIN_VJ_STATES) { 94943545Sbrian /* Ok, we can do that */ 95043545Sbrian ipcp->peer_compproto = compproto; 95143545Sbrian ipcp->heis1172 = 0; 95243545Sbrian memcpy(dec->ackend, cp, length); 95343545Sbrian dec->ackend += length; 95443545Sbrian } else { 95543545Sbrian /* Get as close as we can to what he wants */ 95643545Sbrian ipcp->heis1172 = 0; 95743545Sbrian memcpy(dec->nakend, cp, 2); 95843545Sbrian pcomp->slots = pcomp->slots < MIN_VJ_STATES ? 95943545Sbrian MIN_VJ_STATES : MAX_VJ_STATES; 96043545Sbrian memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 96143545Sbrian dec->nakend += length; 96243545Sbrian } 9636059Samurai } else { 96443545Sbrian /* What we really want */ 96536285Sbrian memcpy(dec->nakend, cp, 2); 9666059Samurai pcomp->proto = htons(PROTO_VJCOMP); 96736285Sbrian pcomp->slots = DEF_VJ_STATES; 96843545Sbrian pcomp->compcid = 1; 96936285Sbrian memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 97036285Sbrian dec->nakend += length; 9716059Samurai } 9726059Samurai break; 9736059Samurai default: 97436285Sbrian memcpy(dec->rejend, cp, length); 97536285Sbrian dec->rejend += length; 9766059Samurai break; 9776059Samurai } 9786059Samurai } 9796059Samurai break; 98040561Sbrian 9816059Samurai case MODE_NAK: 98243545Sbrian if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 98343545Sbrian if (pcomp->slots > MAX_VJ_STATES) 98443545Sbrian pcomp->slots = MAX_VJ_STATES; 98543545Sbrian else if (pcomp->slots < MIN_VJ_STATES) 98643545Sbrian pcomp->slots = MIN_VJ_STATES; 98743545Sbrian compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) + 98843545Sbrian pcomp->compcid; 98943545Sbrian } else 99043545Sbrian compproto = 0; 99136285Sbrian log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 99236285Sbrian tbuff, ipcp->my_compproto, compproto); 99343545Sbrian ipcp->my_compproto = compproto; 9946059Samurai break; 99540561Sbrian 9966059Samurai case MODE_REJ: 99736285Sbrian ipcp->peer_reject |= (1 << type); 9986059Samurai break; 9996059Samurai } 10006059Samurai break; 100140561Sbrian 100228679Sbrian case TY_IPADDRS: /* RFC1172 */ 100338814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 100438814Sbrian memcpy(&dstipaddr.s_addr, cp + 6, 4); 100531962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 100636285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 10076059Samurai 100831034Sbrian switch (mode_type) { 10096059Samurai case MODE_REQ: 101036285Sbrian ipcp->peer_ip = ipaddr; 101136285Sbrian ipcp->my_ip = dstipaddr; 101236285Sbrian memcpy(dec->ackend, cp, length); 101336285Sbrian dec->ackend += length; 10146059Samurai break; 101540561Sbrian 10166059Samurai case MODE_NAK: 101731962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff, 101836285Sbrian inet_ntoa(ipcp->my_ip)); 101936285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 102036285Sbrian ipcp->my_ip = ipaddr; 102136285Sbrian ipcp->peer_ip = dstipaddr; 10226059Samurai break; 102340561Sbrian 10246059Samurai case MODE_REJ: 102536285Sbrian ipcp->peer_reject |= (1 << type); 10266059Samurai break; 10276059Samurai } 10286059Samurai break; 102918752Sjkh 103036285Sbrian case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ 103136285Sbrian case TY_SECONDARY_DNS: 103238814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 103336285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 103418752Sjkh 103531034Sbrian switch (mode_type) { 103618752Sjkh case MODE_REQ: 103736285Sbrian if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { 103836285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 103936285Sbrian memcpy(dec->rejend, cp, length); 104036285Sbrian dec->rejend += length; 104136285Sbrian break; 104236285Sbrian } 104336285Sbrian if (!gotdns) { 104436285Sbrian dns[0] = ipcp->cfg.ns.dns[0]; 104536285Sbrian dns[1] = ipcp->cfg.ns.dns[1]; 104636285Sbrian if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) 104736285Sbrian getdns(ipcp, dns); 104836285Sbrian gotdns = 1; 104936285Sbrian } 105036285Sbrian have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; 105128679Sbrian 105236285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 105318752Sjkh /* 105436285Sbrian * The client has got the DNS stuff wrong (first request) so 105528974Sbrian * we'll tell 'em how it is 105628679Sbrian */ 105736285Sbrian memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ 105836285Sbrian memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); 105936285Sbrian dec->nakend += length; 106036285Sbrian } else { 106136285Sbrian /* 106236285Sbrian * Otherwise they have it right (this time) so we send a ack packet 106336285Sbrian * back confirming it... end of story 106436285Sbrian */ 106536285Sbrian memcpy(dec->ackend, cp, length); 106636285Sbrian dec->ackend += length; 106736285Sbrian } 106818752Sjkh break; 106940561Sbrian 107028679Sbrian case MODE_NAK: /* what does this mean?? */ 107136285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 107236285Sbrian gotdnsnak = 1; 107338814Sbrian memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4); 107436285Sbrian } 107518752Sjkh break; 107640561Sbrian 107736285Sbrian case MODE_REJ: /* Can't do much, stop asking */ 107836285Sbrian ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); 107918752Sjkh break; 108018752Sjkh } 108118752Sjkh break; 108218752Sjkh 108336285Sbrian case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ 108418752Sjkh case TY_SECONDARY_NBNS: 108538814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 108636285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 108736285Sbrian 108831034Sbrian switch (mode_type) { 108918752Sjkh case MODE_REQ: 109036285Sbrian have_ip.s_addr = 109136285Sbrian ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; 109236285Sbrian 109336285Sbrian if (have_ip.s_addr == INADDR_ANY) { 109436285Sbrian log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); 109536285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 109636285Sbrian memcpy(dec->rejend, cp, length); 109736285Sbrian dec->rejend += length; 109818752Sjkh break; 109936285Sbrian } 110036285Sbrian 110136285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 110236285Sbrian memcpy(dec->nakend, cp, 2); 110336285Sbrian memcpy(dec->nakend+2, &have_ip.s_addr, length); 110436285Sbrian dec->nakend += length; 110536285Sbrian } else { 110636285Sbrian memcpy(dec->ackend, cp, length); 110736285Sbrian dec->ackend += length; 110836285Sbrian } 110918752Sjkh break; 111040561Sbrian 111118752Sjkh case MODE_NAK: 111236285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 111318752Sjkh break; 111440561Sbrian 111518752Sjkh case MODE_REJ: 111636285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 111718752Sjkh break; 111818752Sjkh } 111918752Sjkh break; 112018752Sjkh 11216059Samurai default: 112236285Sbrian if (mode_type != MODE_NOP) { 112336285Sbrian ipcp->my_reject |= (1 << type); 112436285Sbrian memcpy(dec->rejend, cp, length); 112536285Sbrian dec->rejend += length; 112636285Sbrian } 11276059Samurai break; 11286059Samurai } 11296059Samurai plen -= length; 11306059Samurai cp += length; 11316059Samurai } 113236285Sbrian 113336285Sbrian if (gotdnsnak) 113436285Sbrian if (!setdns(ipcp, dnsnak)) { 113536285Sbrian ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); 113636285Sbrian ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); 113736285Sbrian } 113836285Sbrian 113936285Sbrian if (mode_type != MODE_NOP) { 114036285Sbrian if (dec->rejend != dec->rej) { 114136285Sbrian /* rejects are preferred */ 114236285Sbrian dec->ackend = dec->ack; 114336285Sbrian dec->nakend = dec->nak; 114436285Sbrian } else if (dec->nakend != dec->nak) 114536285Sbrian /* then NAKs */ 114636285Sbrian dec->ackend = dec->ack; 114736285Sbrian } 11486059Samurai} 11496059Samurai 11506059Samuraivoid 115136285Sbrianipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp) 11526059Samurai{ 115336285Sbrian /* Got PROTO_IPCP from link */ 115436285Sbrian if (bundle_Phase(bundle) == PHASE_NETWORK) 115536285Sbrian fsm_Input(&ipcp->fsm, bp); 115636285Sbrian else { 115736285Sbrian if (bundle_Phase(bundle) < PHASE_NETWORK) 115836285Sbrian log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", 115936285Sbrian ipcp->fsm.link->name, bundle_PhaseName(bundle)); 116036285Sbrian mbuf_Free(bp); 116136285Sbrian } 11626059Samurai} 116332267Sbrian 116432267Sbrianint 116543313Sbrianipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr) 116643313Sbrian{ 116743313Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 116843313Sbrian 116943313Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 117043313Sbrian iplist_reset(&ipcp->cfg.peer_list); 117143313Sbrian ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr; 117243313Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 117343313Sbrian ipcp->cfg.peer_range.width = 32; 117443313Sbrian 117543313Sbrian if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0) 117643313Sbrian return 0; 117743313Sbrian 117843313Sbrian return 1; /* Ok */ 117943313Sbrian} 118043313Sbrian 118143313Sbrianint 118236285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 118332267Sbrian{ 118436285Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 118536285Sbrian 118636285Sbrian /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 118736285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 118836285Sbrian iplist_reset(&ipcp->cfg.peer_list); 118932267Sbrian if (strpbrk(hisaddr, ",-")) { 119036285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); 119136285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 119236285Sbrian iplist_setrandpos(&ipcp->cfg.peer_list); 119336285Sbrian ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); 119436285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 119536285Sbrian log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); 119632267Sbrian return(0); 119732267Sbrian } 119836285Sbrian ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; 119936285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 120036285Sbrian ipcp->cfg.peer_range.width = 32; 120132267Sbrian } else { 120236285Sbrian log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); 120332267Sbrian return 0; 120432267Sbrian } 120543313Sbrian } else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr, 120636285Sbrian &ipcp->cfg.peer_range.mask, 120736285Sbrian &ipcp->cfg.peer_range.width) != 0) { 120836285Sbrian ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; 120932267Sbrian 121036285Sbrian if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, 121140561Sbrian ipcp->cfg.peer_range.ipaddr, 0) < 0) 121232267Sbrian return 0; 121332267Sbrian } else 121432267Sbrian return 0; 121532267Sbrian 121632267Sbrian return 1; 121732267Sbrian} 121844455Sbrian 121944455Sbrianstruct in_addr 122044455Sbrianaddr2mask(struct in_addr addr) 122144455Sbrian{ 122244455Sbrian u_int32_t haddr = ntohl(addr.s_addr); 122344455Sbrian 122444455Sbrian haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET : 122544455Sbrian IN_CLASSB(haddr) ? IN_CLASSB_NET : 122644455Sbrian IN_CLASSC_NET; 122744455Sbrian addr.s_addr = htonl(haddr); 122844455Sbrian 122944455Sbrian return addr; 123044455Sbrian} 1231