ipcp.c revision 39395
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 * 2039395Sbrian * $Id: ipcp.c,v 1.65 1998/09/04 18:25:59 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> 3130715Sbrian#include <netdb.h> 3236285Sbrian#include <net/if.h> 3336285Sbrian#include <sys/sockio.h> 3436285Sbrian#include <sys/un.h> 3530715Sbrian 3636285Sbrian#include <fcntl.h> 3736285Sbrian#include <resolv.h> 3832614Sbrian#include <stdlib.h> 3930715Sbrian#include <string.h> 4036285Sbrian#include <sys/errno.h> 4136285Sbrian#include <termios.h> 4230715Sbrian#include <unistd.h> 4330715Sbrian 4439395Sbrian#ifndef NOALIAS 4539395Sbrian#ifdef __OpenBSD__ 4639395Sbrian#include "alias.h" 4739395Sbrian#else 4839395Sbrian#include <alias.h> 4939395Sbrian#endif 5039395Sbrian#endif 5138814Sbrian#include "ua.h" 5237009Sbrian#include "defs.h" 5331343Sbrian#include "command.h" 5430715Sbrian#include "mbuf.h" 5530715Sbrian#include "log.h" 5630715Sbrian#include "timer.h" 5729048Sbrian#include "fsm.h" 5829048Sbrian#include "lcpproto.h" 5929048Sbrian#include "lcp.h" 6031690Sbrian#include "iplist.h" 6136285Sbrian#include "throughput.h" 6236285Sbrian#include "slcompress.h" 6338557Sbrian#include "lqr.h" 6438557Sbrian#include "hdlc.h" 6529048Sbrian#include "ipcp.h" 6636285Sbrian#include "filter.h" 6736285Sbrian#include "descriptor.h" 6830715Sbrian#include "vjcomp.h" 6936285Sbrian#include "async.h" 7036285Sbrian#include "ccp.h" 7136285Sbrian#include "link.h" 7236285Sbrian#include "physical.h" 7336285Sbrian#include "mp.h" 7436285Sbrian#include "bundle.h" 7536285Sbrian#include "id.h" 7636285Sbrian#include "arp.h" 7736285Sbrian#include "systems.h" 7836285Sbrian#include "prompt.h" 7931690Sbrian#include "route.h" 806059Samurai 8136285Sbrian#undef REJECTED 8236285Sbrian#define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) 8336285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t') 8436285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.') 856059Samurai 8636285Sbrianstruct compreq { 8736285Sbrian u_short proto; 8836285Sbrian u_char slots; 8936285Sbrian u_char compcid; 9036285Sbrian}; 916059Samurai 9236285Sbrianstatic int IpcpLayerUp(struct fsm *); 9336285Sbrianstatic void IpcpLayerDown(struct fsm *); 9426516Sbrianstatic void IpcpLayerStart(struct fsm *); 9526516Sbrianstatic void IpcpLayerFinish(struct fsm *); 9626516Sbrianstatic void IpcpInitRestartCounter(struct fsm *); 9736285Sbrianstatic void IpcpSendConfigReq(struct fsm *); 9836285Sbrianstatic void IpcpSentTerminateReq(struct fsm *); 9936285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char); 10036285Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, int, int, 10136285Sbrian struct fsm_decode *); 1026059Samurai 10336285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = { 1046059Samurai IpcpLayerUp, 1056059Samurai IpcpLayerDown, 1066059Samurai IpcpLayerStart, 1076059Samurai IpcpLayerFinish, 1086059Samurai IpcpInitRestartCounter, 1096059Samurai IpcpSendConfigReq, 11036285Sbrian IpcpSentTerminateReq, 1116059Samurai IpcpSendTerminateAck, 1126059Samurai IpcpDecodeConfig, 11336285Sbrian fsm_NullRecvResetReq, 11436285Sbrian fsm_NullRecvResetAck 1156059Samurai}; 1166059Samurai 11731343Sbrianstatic const char *cftypes[] = { 11831171Sbrian /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 11931171Sbrian "???", 12031171Sbrian "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ 12131171Sbrian "COMPPROTO", /* 2: IP-Compression-Protocol */ 12231171Sbrian "IPADDR", /* 3: IP-Address */ 1236059Samurai}; 1246059Samurai 12531962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 12631171Sbrian 12731343Sbrianstatic const char *cftypes128[] = { 12831171Sbrian /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 12931171Sbrian "???", 13031171Sbrian "PRIDNS", /* 129: Primary DNS Server Address */ 13131171Sbrian "PRINBNS", /* 130: Primary NBNS Server Address */ 13231171Sbrian "SECDNS", /* 131: Secondary DNS Server Address */ 13331171Sbrian "SECNBNS", /* 132: Secondary NBNS Server Address */ 13431171Sbrian}; 13531171Sbrian 13631962Sbrian#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) 13731171Sbrian 13831272Sbrianvoid 13936285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n) 1406059Samurai{ 14136285Sbrian throughput_addin(&ipcp->throughput, n); 1426059Samurai} 1436059Samurai 14431272Sbrianvoid 14536285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n) 1466059Samurai{ 14736285Sbrian throughput_addout(&ipcp->throughput, n); 1486059Samurai} 1496059Samurai 15036285Sbrianstatic void 15136285Sbriangetdns(struct ipcp *ipcp, struct in_addr addr[2]) 1526059Samurai{ 15336285Sbrian FILE *fp; 1546059Samurai 15536285Sbrian addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 15636285Sbrian if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 15736285Sbrian char buf[LINE_LEN], *cp, *end; 15836285Sbrian int n; 15936285Sbrian 16036285Sbrian n = 0; 16136285Sbrian buf[sizeof buf - 1] = '\0'; 16236285Sbrian while (fgets(buf, sizeof buf - 1, fp)) { 16336285Sbrian if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) { 16436285Sbrian for (cp = buf + 11; issep(*cp); cp++) 16536285Sbrian ; 16636285Sbrian for (end = cp; isip(*end); end++) 16736285Sbrian ; 16836285Sbrian *end = '\0'; 16936285Sbrian if (inet_aton(cp, addr+n) && ++n == 2) 17036285Sbrian break; 17136285Sbrian } 17236285Sbrian } 17336285Sbrian if (n == 1) 17436285Sbrian addr[1] = addr[0]; 17536285Sbrian fclose(fp); 17632614Sbrian } 17736285Sbrian} 17829048Sbrian 17936285Sbrianstatic int 18036285Sbriansetdns(struct ipcp *ipcp, struct in_addr addr[2]) 18136285Sbrian{ 18236285Sbrian FILE *fp; 18336285Sbrian char wbuf[LINE_LEN + 54]; 18436285Sbrian int wlen; 18526516Sbrian 18636285Sbrian if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) { 18736285Sbrian struct in_addr old[2]; 18831272Sbrian 18936285Sbrian getdns(ipcp, old); 19036285Sbrian if (addr[0].s_addr == INADDR_ANY) 19136285Sbrian addr[0] = old[0]; 19236285Sbrian if (addr[1].s_addr == INADDR_ANY) 19336285Sbrian addr[1] = old[1]; 19436285Sbrian } 19536285Sbrian 19636285Sbrian if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) { 19736285Sbrian log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n", 19836285Sbrian _PATH_RESCONF); 19936285Sbrian return 0; 20036285Sbrian } 20136285Sbrian 20236285Sbrian wlen = 0; 20336285Sbrian if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 20436285Sbrian char buf[LINE_LEN]; 20536285Sbrian int len; 20636285Sbrian 20736285Sbrian buf[sizeof buf - 1] = '\0'; 20836285Sbrian while (fgets(buf, sizeof buf - 1, fp)) { 20936285Sbrian if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) { 21036285Sbrian len = strlen(buf); 21136285Sbrian if (len > sizeof wbuf - wlen) { 21236285Sbrian log_Printf(LogWARN, "%s: Can only cope with max file size %d\n", 21336285Sbrian _PATH_RESCONF, LINE_LEN); 21436285Sbrian fclose(fp); 21536285Sbrian return 0; 21636285Sbrian } 21736285Sbrian memcpy(wbuf + wlen, buf, len); 21836285Sbrian wlen += len; 21936285Sbrian } 22036285Sbrian } 22136285Sbrian fclose(fp); 22236285Sbrian } 22336285Sbrian 22436285Sbrian if (addr[0].s_addr != INADDR_ANY) { 22536285Sbrian snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 22636285Sbrian inet_ntoa(addr[0])); 22736285Sbrian log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11); 22836285Sbrian wlen += strlen(wbuf + wlen); 22936285Sbrian } 23036285Sbrian 23136285Sbrian if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) { 23236285Sbrian snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 23336285Sbrian inet_ntoa(addr[1])); 23436285Sbrian log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11); 23536285Sbrian wlen += strlen(wbuf + wlen); 23636285Sbrian } 23736285Sbrian 23836285Sbrian if (wlen) { 23936285Sbrian int fd; 24036285Sbrian 24136285Sbrian if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) { 24236285Sbrian if (write(fd, wbuf, wlen) != wlen) { 24336285Sbrian log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno)); 24436285Sbrian close(fd); 24536285Sbrian return 0; 24636285Sbrian } 24736285Sbrian if (ftruncate(fd, wlen) == -1) { 24836285Sbrian log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno)); 24936285Sbrian close(fd); 25036285Sbrian return 0; 25136285Sbrian } 25236285Sbrian close(fd); 25336285Sbrian } else { 25436285Sbrian log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno)); 25536285Sbrian return 0; 25636285Sbrian } 25736285Sbrian } 25836285Sbrian 25936285Sbrian return 1; 2606059Samurai} 2616059Samurai 26236285Sbrianint 26336285Sbrianipcp_Show(struct cmdargs const *arg) 2646059Samurai{ 26536285Sbrian struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 2666059Samurai 26736285Sbrian prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, 26836285Sbrian State2Nam(ipcp->fsm.state)); 26936285Sbrian if (ipcp->fsm.state == ST_OPENED) { 27036285Sbrian prompt_Printf(arg->prompt, " His side: %s, %s\n", 27136285Sbrian inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); 27236285Sbrian prompt_Printf(arg->prompt, " My side: %s, %s\n", 27336285Sbrian inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); 2746059Samurai } 27536285Sbrian 27636285Sbrian if (ipcp->route) { 27736285Sbrian prompt_Printf(arg->prompt, "\n"); 27836285Sbrian route_ShowSticky(arg->prompt, ipcp->route); 27936285Sbrian } 28036285Sbrian 28136285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 28236285Sbrian prompt_Printf(arg->prompt, " My Address: %s/%d", 28336285Sbrian inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width); 28436285Sbrian 28536285Sbrian if (ipcp->cfg.HaveTriggerAddress) 28636285Sbrian prompt_Printf(arg->prompt, " (trigger with %s)", 28736285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 28836285Sbrian prompt_Printf(arg->prompt, "\n VJ compression: %s (%d slots %s slot " 28936285Sbrian "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), 29036285Sbrian ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); 29136285Sbrian 29236285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) 29336285Sbrian prompt_Printf(arg->prompt, " His Address: %s\n", 29436285Sbrian ipcp->cfg.peer_list.src); 29536285Sbrian else 29636285Sbrian prompt_Printf(arg->prompt, " His Address: %s/%d\n", 29736285Sbrian inet_ntoa(ipcp->cfg.peer_range.ipaddr), 29836285Sbrian ipcp->cfg.peer_range.width); 29936285Sbrian 30036285Sbrian prompt_Printf(arg->prompt, " DNS: %s, ", 30136285Sbrian inet_ntoa(ipcp->cfg.ns.dns[0])); 30236285Sbrian prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]), 30336285Sbrian command_ShowNegval(ipcp->cfg.ns.dns_neg)); 30436285Sbrian prompt_Printf(arg->prompt, " NetBIOS NS: %s, ", 30536285Sbrian inet_ntoa(ipcp->cfg.ns.nbns[0])); 30636285Sbrian prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1])); 30736285Sbrian 30836285Sbrian prompt_Printf(arg->prompt, "\n"); 30936285Sbrian throughput_disp(&ipcp->throughput, arg->prompt); 31036285Sbrian 31136285Sbrian return 0; 3126059Samurai} 3136059Samurai 31432614Sbrianint 31536285Sbrianipcp_vjset(struct cmdargs const *arg) 31632614Sbrian{ 31736285Sbrian if (arg->argc != arg->argn+2) 31832614Sbrian return -1; 31936285Sbrian if (!strcasecmp(arg->argv[arg->argn], "slots")) { 32032614Sbrian int slots; 32132614Sbrian 32236285Sbrian slots = atoi(arg->argv[arg->argn+1]); 32332614Sbrian if (slots < 4 || slots > 16) 32432614Sbrian return 1; 32536285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slots = slots; 32632614Sbrian return 0; 32736285Sbrian } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { 32836285Sbrian if (!strcasecmp(arg->argv[arg->argn+1], "on")) 32936285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; 33036285Sbrian else if (!strcasecmp(arg->argv[arg->argn+1], "off")) 33136285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; 33232614Sbrian else 33332614Sbrian return 2; 33432614Sbrian return 0; 33532614Sbrian } 33632614Sbrian return -1; 33732614Sbrian} 33832614Sbrian 33936285Sbrianvoid 34036285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, 34136285Sbrian const struct fsm_parent *parent) 34232614Sbrian{ 34336285Sbrian struct hostent *hp; 34436285Sbrian char name[MAXHOSTNAMELEN]; 34536285Sbrian static const char *timer_names[] = 34636285Sbrian {"IPCP restart", "IPCP openmode", "IPCP stopped"}; 34736285Sbrian 34836285Sbrian fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP, 34936285Sbrian bundle, l, parent, &ipcp_Callbacks, timer_names); 35036285Sbrian 35136285Sbrian ipcp->route = NULL; 35236285Sbrian ipcp->cfg.vj.slots = DEF_VJ_STATES; 35336285Sbrian ipcp->cfg.vj.slotcomp = 1; 35436285Sbrian memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 35536285Sbrian if (gethostname(name, sizeof name) == 0) { 35636285Sbrian hp = gethostbyname(name); 35736285Sbrian if (hp && hp->h_addrtype == AF_INET) { 35836285Sbrian memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); 35936285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 36036285Sbrian ipcp->cfg.peer_range.width = 32; 36136285Sbrian } 36232614Sbrian } 36336285Sbrian ipcp->cfg.netmask.s_addr = INADDR_ANY; 36436285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 36536285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, ""); 36636285Sbrian ipcp->cfg.HaveTriggerAddress = 0; 36736285Sbrian 36836285Sbrian ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY; 36936285Sbrian ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY; 37036285Sbrian ipcp->cfg.ns.dns_neg = 0; 37136285Sbrian ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; 37236285Sbrian ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; 37336285Sbrian 37436285Sbrian ipcp->cfg.fsmretry = DEF_FSMRETRY; 37536285Sbrian ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; 37636285Sbrian 37736285Sbrian memset(&ipcp->vj, '\0', sizeof ipcp->vj); 37836285Sbrian 37936285Sbrian ipcp->my_ifip.s_addr = INADDR_ANY; 38036285Sbrian ipcp->peer_ifip.s_addr = INADDR_ANY; 38136285Sbrian 38236285Sbrian throughput_init(&ipcp->throughput); 38338557Sbrian memset(ipcp->Queue, '\0', sizeof ipcp->Queue); 38436285Sbrian ipcp_Setup(ipcp); 38532614Sbrian} 38632614Sbrian 3876059Samuraivoid 38836285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l) 3896059Samurai{ 39036285Sbrian ipcp->fsm.link = l; 39136285Sbrian} 39236285Sbrian 39336285Sbrianvoid 39436285Sbrianipcp_Setup(struct ipcp *ipcp) 39536285Sbrian{ 39636285Sbrian int pos; 39736285Sbrian 39836285Sbrian ipcp->fsm.open_mode = 0; 39936285Sbrian ipcp->fsm.maxconfig = 10; 40036285Sbrian 40136285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 40236285Sbrian if (ipcp->my_ifip.s_addr != INADDR_ANY && 40336285Sbrian (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1) 40436285Sbrian ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos); 40536285Sbrian else 40636285Sbrian ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); 40736285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 40836285Sbrian ipcp->cfg.peer_range.width = 32; 4096059Samurai } 4109440Samurai 41136285Sbrian ipcp->heis1172 = 0; 41236285Sbrian 41336285Sbrian ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; 41436285Sbrian ipcp->peer_compproto = 0; 41536285Sbrian 41636285Sbrian if (ipcp->cfg.HaveTriggerAddress) { 41736285Sbrian /* 41836285Sbrian * Some implementations of PPP require that we send a 41936285Sbrian * *special* value as our address, even though the rfc specifies 42036285Sbrian * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 42136285Sbrian */ 42236285Sbrian ipcp->my_ip = ipcp->cfg.TriggerAddress; 42336285Sbrian log_Printf(LogIPCP, "Using trigger address %s\n", 42436285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 42536285Sbrian } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) == 42636285Sbrian (ipcp->cfg.my_range.ipaddr.s_addr & 42736285Sbrian ipcp->cfg.my_range.mask.s_addr)) 42836285Sbrian /* 42936285Sbrian * Otherwise, if we've been assigned an IP number before, we really 43036285Sbrian * want to keep the same IP number so that we can keep any existing 43136285Sbrian * connections that are bound to that IP. 43236285Sbrian */ 43336285Sbrian ipcp->my_ip = ipcp->my_ifip; 43436285Sbrian else 43536285Sbrian ipcp->my_ip = ipcp->cfg.my_range.ipaddr; 43636285Sbrian 43736285Sbrian if (IsEnabled(ipcp->cfg.vj.neg)) 43836285Sbrian ipcp->my_compproto = (PROTO_VJCOMP << 16) + 43936285Sbrian ((ipcp->cfg.vj.slots - 1) << 8) + 44036285Sbrian ipcp->cfg.vj.slotcomp; 44136285Sbrian else 44236285Sbrian ipcp->my_compproto = 0; 44336285Sbrian sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); 44436285Sbrian 44536285Sbrian ipcp->peer_reject = 0; 44636285Sbrian ipcp->my_reject = 0; 44736285Sbrian} 44836285Sbrian 44936285Sbrianstatic int 45036285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, 45136285Sbrian struct in_addr hisaddr, int silent) 45236285Sbrian{ 45336285Sbrian struct sockaddr_in *sock_in; 45436285Sbrian int s; 45537200Sbrian u_int32_t mask, addr; 45636285Sbrian struct ifaliasreq ifra; 45736285Sbrian 45836285Sbrian /* If given addresses are alreay set, then ignore this request */ 45936285Sbrian if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr && 46036285Sbrian bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr) 46136285Sbrian return 0; 46236285Sbrian 46336285Sbrian ipcp_CleanInterface(&bundle->ncp.ipcp); 46436285Sbrian 46536285Sbrian s = ID0socket(AF_INET, SOCK_DGRAM, 0); 46636285Sbrian if (s < 0) { 46737019Sbrian log_Printf(LogERROR, "SetIPaddress: socket(): %s\n", strerror(errno)); 46836285Sbrian return (-1); 4699440Samurai } 47036285Sbrian 47136285Sbrian memset(&ifra, '\0', sizeof ifra); 47236285Sbrian strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1); 47336285Sbrian ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 47436285Sbrian 47536285Sbrian /* Set interface address */ 47636285Sbrian sock_in = (struct sockaddr_in *)&ifra.ifra_addr; 47736285Sbrian sock_in->sin_family = AF_INET; 47836285Sbrian sock_in->sin_addr = myaddr; 47936285Sbrian sock_in->sin_len = sizeof *sock_in; 48036285Sbrian 48136285Sbrian /* Set destination address */ 48236285Sbrian sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr; 48336285Sbrian sock_in->sin_family = AF_INET; 48436285Sbrian sock_in->sin_addr = hisaddr; 48536285Sbrian sock_in->sin_len = sizeof *sock_in; 48636285Sbrian 48736285Sbrian addr = ntohl(myaddr.s_addr); 48836285Sbrian if (IN_CLASSA(addr)) 48936285Sbrian mask = IN_CLASSA_NET; 49036285Sbrian else if (IN_CLASSB(addr)) 49136285Sbrian mask = IN_CLASSB_NET; 4926059Samurai else 49336285Sbrian mask = IN_CLASSC_NET; 49436285Sbrian 49536285Sbrian /* if subnet mask is given, use it instead of class mask */ 49636285Sbrian if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY && 49736285Sbrian (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask) 49836285Sbrian mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr); 49936285Sbrian 50036285Sbrian sock_in = (struct sockaddr_in *)&ifra.ifra_mask; 50136285Sbrian sock_in->sin_family = AF_INET; 50236285Sbrian sock_in->sin_addr.s_addr = htonl(mask); 50336285Sbrian sock_in->sin_len = sizeof *sock_in; 50436285Sbrian 50536285Sbrian if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { 50636285Sbrian if (!silent) 50737019Sbrian log_Printf(LogERROR, "SetIPaddress: ioctl(SIOCAIFADDR): %s\n", 50836285Sbrian strerror(errno)); 50936285Sbrian close(s); 51036285Sbrian return (-1); 51136285Sbrian } 51236285Sbrian 51336285Sbrian if (Enabled(bundle, OPT_SROUTES)) 51436285Sbrian route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); 51536285Sbrian 51636285Sbrian bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr; 51736285Sbrian bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr; 51836285Sbrian 51936285Sbrian if (Enabled(bundle, OPT_PROXY)) 52036285Sbrian arp_SetProxy(bundle, bundle->ncp.ipcp.peer_ifip, s); 52136285Sbrian 52236285Sbrian close(s); 52336285Sbrian return (0); 5246059Samurai} 5256059Samurai 52636285Sbrianstatic struct in_addr 52736285SbrianChooseHisAddr(struct bundle *bundle, const struct in_addr gw) 52836285Sbrian{ 52936285Sbrian struct in_addr try; 53037210Sbrian u_long f; 53136285Sbrian 53236285Sbrian for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { 53336285Sbrian try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); 53437210Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n", 53536285Sbrian f, inet_ntoa(try)); 53636285Sbrian if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { 53736285Sbrian log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); 53836285Sbrian break; 53936285Sbrian } 54036285Sbrian } 54136285Sbrian 54236285Sbrian if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { 54336285Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 54436285Sbrian try.s_addr = INADDR_ANY; 54536285Sbrian } 54636285Sbrian 54736285Sbrian return try; 54836285Sbrian} 54936285Sbrian 5506059Samuraistatic void 55128679SbrianIpcpInitRestartCounter(struct fsm * fp) 5526059Samurai{ 55336285Sbrian /* Set fsm timer load */ 55436285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 55536285Sbrian 55636285Sbrian fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS; 55738174Sbrian fp->restart = DEF_REQs; 5586059Samurai} 5596059Samurai 5606059Samuraistatic void 56136285SbrianIpcpSendConfigReq(struct fsm *fp) 5626059Samurai{ 56336285Sbrian /* Send config REQ please */ 56436285Sbrian struct physical *p = link2physical(fp->link); 56536285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 56636285Sbrian u_char buff[24]; 56736285Sbrian struct lcp_opt *o; 5686059Samurai 56936285Sbrian o = (struct lcp_opt *)buff; 57036285Sbrian 57136285Sbrian if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 57238814Sbrian memcpy(o->data, &ipcp->my_ip.s_addr, 4); 57336285Sbrian INC_LCP_OPT(TY_IPADDR, 6, o); 57431514Sbrian } 57531514Sbrian 57636285Sbrian if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 57736285Sbrian if (ipcp->heis1172) { 57838814Sbrian u_int16_t proto = PROTO_VJCOMP; 57938814Sbrian 58038814Sbrian ua_htons(&proto, o->data); 58136285Sbrian INC_LCP_OPT(TY_COMPPROTO, 4, o); 58231514Sbrian } else { 58338814Sbrian ua_htonl(&ipcp->my_compproto, o->data); 58436285Sbrian INC_LCP_OPT(TY_COMPPROTO, 6, o); 58531514Sbrian } 5866059Samurai } 58736285Sbrian 58836285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg) && 58936285Sbrian !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && 59036285Sbrian !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { 59136285Sbrian struct in_addr dns[2]; 59236285Sbrian getdns(ipcp, dns); 59338814Sbrian memcpy(o->data, &dns[0].s_addr, 4); 59436285Sbrian INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); 59538814Sbrian memcpy(o->data, &dns[1].s_addr, 4); 59636285Sbrian INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); 59736285Sbrian } 59836285Sbrian 59936285Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff); 6006059Samurai} 6016059Samurai 6026059Samuraistatic void 60336285SbrianIpcpSentTerminateReq(struct fsm * fp) 6046059Samurai{ 60536285Sbrian /* Term REQ just sent by FSM */ 6066059Samurai} 6076059Samurai 6086059Samuraistatic void 60936285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id) 6106059Samurai{ 61136285Sbrian /* Send Term ACK please */ 61236285Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0); 6136059Samurai} 6146059Samurai 6156059Samuraistatic void 61637160SbrianIpcpLayerStart(struct fsm *fp) 6176059Samurai{ 61836285Sbrian /* We're about to start up ! */ 61937160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 62037160Sbrian 62137210Sbrian log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name); 62237160Sbrian throughput_start(&ipcp->throughput, "IPCP throughput", 62337160Sbrian Enabled(fp->bundle, OPT_THROUGHPUT)); 62436285Sbrian 62536465Sbrian /* This is where we should be setting up the interface in AUTO mode */ 6266059Samurai} 6276059Samurai 6286059Samuraistatic void 62936285SbrianIpcpLayerFinish(struct fsm *fp) 6306059Samurai{ 63136285Sbrian /* We're now down */ 63237160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 63337160Sbrian 63437210Sbrian log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name); 63537160Sbrian throughput_stop(&ipcp->throughput); 63637160Sbrian throughput_log(&ipcp->throughput, LogIPCP, NULL); 6376059Samurai} 6386059Samurai 63936285Sbrianvoid 64036285Sbrianipcp_CleanInterface(struct ipcp *ipcp) 6416059Samurai{ 64236285Sbrian struct ifaliasreq ifra; 64336285Sbrian struct sockaddr_in *me, *peer; 64436285Sbrian int s; 64536285Sbrian 64636285Sbrian s = ID0socket(AF_INET, SOCK_DGRAM, 0); 64736285Sbrian if (s < 0) { 64836285Sbrian log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno)); 64936285Sbrian return; 65036285Sbrian } 65136285Sbrian 65236285Sbrian route_Clean(ipcp->fsm.bundle, ipcp->route); 65336285Sbrian 65436285Sbrian if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) 65536285Sbrian arp_ClearProxy(ipcp->fsm.bundle, ipcp->peer_ifip, s); 65636285Sbrian 65736285Sbrian if (ipcp->my_ifip.s_addr != INADDR_ANY || 65836285Sbrian ipcp->peer_ifip.s_addr != INADDR_ANY) { 65936285Sbrian memset(&ifra, '\0', sizeof ifra); 66036285Sbrian strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifp.Name, 66136285Sbrian sizeof ifra.ifra_name - 1); 66236285Sbrian ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 66336285Sbrian me = (struct sockaddr_in *)&ifra.ifra_addr; 66436285Sbrian peer = (struct sockaddr_in *)&ifra.ifra_broadaddr; 66536285Sbrian me->sin_family = peer->sin_family = AF_INET; 66636285Sbrian me->sin_len = peer->sin_len = sizeof(struct sockaddr_in); 66736285Sbrian me->sin_addr = ipcp->my_ifip; 66836285Sbrian peer->sin_addr = ipcp->peer_ifip; 66936285Sbrian if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) 67036285Sbrian log_Printf(LogERROR, "ipcp_CleanInterface: ioctl(SIOCDIFADDR): %s\n", 67136285Sbrian strerror(errno)); 67236285Sbrian ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY; 67336285Sbrian } 67436285Sbrian 67536285Sbrian close(s); 6766059Samurai} 6776059Samurai 6786059Samuraistatic void 67936285SbrianIpcpLayerDown(struct fsm *fp) 6806059Samurai{ 68136285Sbrian /* About to come down */ 68236285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 68336285Sbrian const char *s; 6846059Samurai 68536285Sbrian s = inet_ntoa(ipcp->peer_ifip); 68637210Sbrian log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s); 68730187Sbrian 68836285Sbrian /* 68936285Sbrian * XXX this stuff should really live in the FSM. Our config should 69036285Sbrian * associate executable sections in files with events. 69136285Sbrian */ 69237008Sbrian if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) { 69336285Sbrian if (bundle_GetLabel(fp->bundle)) { 69436285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 69537008Sbrian LINKDOWNFILE, NULL, NULL) < 0) 69637008Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 69736285Sbrian } else 69837008Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 69936285Sbrian } 70030187Sbrian 70136928Sbrian if (!(ipcp->fsm.bundle->phys_type.all & PHYS_AUTO)) 70236285Sbrian ipcp_CleanInterface(ipcp); 70337160Sbrian 70437160Sbrian ipcp_Setup(ipcp); 70536285Sbrian} 70636285Sbrian 70736285Sbrianint 70836285Sbrianipcp_InterfaceUp(struct ipcp *ipcp) 70936285Sbrian{ 71036285Sbrian if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { 71137019Sbrian log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n"); 71236285Sbrian return 0; 71325630Sbrian } 71436285Sbrian 71531343Sbrian#ifndef NOALIAS 71637191Sbrian if (ipcp->fsm.bundle->AliasEnabled) 71737191Sbrian PacketAliasSetAddress(ipcp->my_ip); 71831343Sbrian#endif 71936285Sbrian 72036285Sbrian return 1; 7216059Samurai} 7226059Samurai 72336285Sbrianstatic int 72436285SbrianIpcpLayerUp(struct fsm *fp) 7256059Samurai{ 72636285Sbrian /* We're now up */ 72736285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 72836285Sbrian char tbuff[100]; 7296059Samurai 73037210Sbrian log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name); 73136285Sbrian snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip)); 73236285Sbrian log_Printf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip)); 73336285Sbrian 73436285Sbrian if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 73536285Sbrian sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); 73636285Sbrian 73736285Sbrian if (!ipcp_InterfaceUp(ipcp)) 73836285Sbrian return 0; 73936285Sbrian 74036285Sbrian /* 74136285Sbrian * XXX this stuff should really live in the FSM. Our config should 74236285Sbrian * associate executable sections in files with events. 74336285Sbrian */ 74437008Sbrian if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, 74537008Sbrian NULL, NULL) < 0) { 74636285Sbrian if (bundle_GetLabel(fp->bundle)) { 74736285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 74837008Sbrian LINKUPFILE, NULL, NULL) < 0) 74937008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 75036285Sbrian } else 75137008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 75236285Sbrian } 75336285Sbrian 75436314Sbrian log_DisplayPrompts(); 75536285Sbrian return 1; 7566059Samurai} 7576059Samurai 7586059Samuraistatic int 75936285SbrianAcceptableAddr(struct in_range *prange, struct in_addr ipaddr) 7606059Samurai{ 76136285Sbrian /* Is the given IP in the given range ? */ 76225661Sbrian return (prange->ipaddr.s_addr & prange->mask.s_addr) == 76328679Sbrian (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 7646059Samurai} 7656059Samurai 7666059Samuraistatic void 76736285SbrianIpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type, 76836285Sbrian struct fsm_decode *dec) 7696059Samurai{ 77036285Sbrian /* Deal with incoming PROTO_IPCP */ 77136285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 7726735Samurai int type, length; 77336285Sbrian u_int32_t compproto; 7746059Samurai struct compreq *pcomp; 77536285Sbrian struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; 77636285Sbrian char tbuff[100], tbuff2[100]; 77736285Sbrian int gotdns, gotdnsnak; 7786059Samurai 77936285Sbrian gotdns = 0; 78036285Sbrian gotdnsnak = 0; 78136285Sbrian dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; 7826059Samurai 7836059Samurai while (plen >= sizeof(struct fsmconfig)) { 7846059Samurai type = *cp; 7856059Samurai length = cp[1]; 78636285Sbrian 78736285Sbrian if (length == 0) { 78836285Sbrian log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); 78936285Sbrian break; 79036285Sbrian } 79136285Sbrian 79231171Sbrian if (type < NCFTYPES) 79331962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); 79431171Sbrian else if (type > 128 && type < 128 + NCFTYPES128) 79531962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); 7966059Samurai else 79731962Sbrian snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); 7986059Samurai 7996059Samurai switch (type) { 8006059Samurai case TY_IPADDR: /* RFC1332 */ 80138814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 80236285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 8036059Samurai 80431034Sbrian switch (mode_type) { 8056059Samurai case MODE_REQ: 80636285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 80731850Sbrian if (ipaddr.s_addr == INADDR_ANY || 80836285Sbrian iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || 80936285Sbrian ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, 81036285Sbrian ipaddr, 1)) { 81136285Sbrian log_Printf(LogIPCP, "%s: Address invalid or already in use\n", 81231690Sbrian inet_ntoa(ipaddr)); 81336285Sbrian if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0) 81436285Sbrian /* 81536285Sbrian * If we've already got a valid address configured for the peer 81636465Sbrian * (in AUTO mode), try NAKing with that so that we don't 81736285Sbrian * have to upset things too much. 81836285Sbrian */ 81936285Sbrian ipcp->peer_ip = ipcp->peer_ifip; 82036285Sbrian else 82136285Sbrian /* Just pick an IP number from our list */ 82236285Sbrian ipcp->peer_ip = ChooseHisAddr 82336285Sbrian (fp->bundle, ipcp->cfg.my_range.ipaddr); 82436285Sbrian 82536285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 82636285Sbrian memcpy(dec->rejend, cp, length); 82736285Sbrian dec->rejend += length; 82831690Sbrian } else { 82936285Sbrian memcpy(dec->nakend, cp, 2); 83036285Sbrian memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); 83136285Sbrian dec->nakend += length; 83231690Sbrian } 83331690Sbrian break; 83431690Sbrian } 83536285Sbrian } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { 83628679Sbrian /* 83736285Sbrian * If destination address is not acceptable, NAK with what we 83828679Sbrian * want to use. 83928679Sbrian */ 84036285Sbrian memcpy(dec->nakend, cp, 2); 84136285Sbrian if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) == 84236285Sbrian (ipcp->cfg.peer_range.ipaddr.s_addr & 84336285Sbrian ipcp->cfg.peer_range.mask.s_addr)) 84436285Sbrian /* We prefer the already-configured address */ 84536285Sbrian memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2); 84636285Sbrian else 84736285Sbrian memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); 84836285Sbrian dec->nakend += length; 84928679Sbrian break; 8506059Samurai } 85136285Sbrian ipcp->peer_ip = ipaddr; 85236285Sbrian memcpy(dec->ackend, cp, length); 85336285Sbrian dec->ackend += length; 8546059Samurai break; 8556059Samurai case MODE_NAK: 85636285Sbrian if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { 85731690Sbrian /* Use address suggested by peer */ 85831962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 85936285Sbrian inet_ntoa(ipcp->my_ip)); 86036285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 86136285Sbrian ipcp->my_ip = ipaddr; 86231690Sbrian } else { 86336285Sbrian log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, 86436285Sbrian "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 86536285Sbrian fsm_Close(&ipcp->fsm); 8666059Samurai } 8676059Samurai break; 8686059Samurai case MODE_REJ: 86936285Sbrian ipcp->peer_reject |= (1 << type); 8706059Samurai break; 8716059Samurai } 8726059Samurai break; 8736059Samurai case TY_COMPPROTO: 87438814Sbrian memcpy(&compproto, cp + 2, 4); 87536285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 8766059Samurai 87731034Sbrian switch (mode_type) { 8786059Samurai case MODE_REQ: 87936285Sbrian if (!IsAccepted(ipcp->cfg.vj.neg)) { 88036285Sbrian memcpy(dec->rejend, cp, length); 88136285Sbrian dec->rejend += length; 8826059Samurai } else { 88328679Sbrian pcomp = (struct compreq *) (cp + 2); 8846059Samurai switch (length) { 88528679Sbrian case 4: /* RFC1172 */ 8866059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 88736285Sbrian log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); 88836285Sbrian ipcp->heis1172 = 1; 88936285Sbrian ipcp->peer_compproto = compproto; 89036285Sbrian memcpy(dec->ackend, cp, length); 89136285Sbrian dec->ackend += length; 8926059Samurai } else { 89336285Sbrian memcpy(dec->nakend, cp, 2); 8946059Samurai pcomp->proto = htons(PROTO_VJCOMP); 89536285Sbrian memcpy(dec->nakend+2, &pcomp, 2); 89636285Sbrian dec->nakend += length; 8976059Samurai } 8986059Samurai break; 89928679Sbrian case 6: /* RFC1332 */ 9006059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP 90136285Sbrian && pcomp->slots <= MAX_VJ_STATES 90236285Sbrian && pcomp->slots >= MIN_VJ_STATES) { 90336285Sbrian ipcp->peer_compproto = compproto; 90436285Sbrian ipcp->heis1172 = 0; 90536285Sbrian memcpy(dec->ackend, cp, length); 90636285Sbrian dec->ackend += length; 9076059Samurai } else { 90836285Sbrian memcpy(dec->nakend, cp, 2); 9096059Samurai pcomp->proto = htons(PROTO_VJCOMP); 91036285Sbrian pcomp->slots = DEF_VJ_STATES; 9116059Samurai pcomp->compcid = 0; 91236285Sbrian memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 91336285Sbrian dec->nakend += length; 9146059Samurai } 9156059Samurai break; 9166059Samurai default: 91736285Sbrian memcpy(dec->rejend, cp, length); 91836285Sbrian dec->rejend += length; 9196059Samurai break; 9206059Samurai } 9216059Samurai } 9226059Samurai break; 9236059Samurai case MODE_NAK: 92436285Sbrian log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 92536285Sbrian tbuff, ipcp->my_compproto, compproto); 92636285Sbrian ipcp->my_compproto = compproto; 9276059Samurai break; 9286059Samurai case MODE_REJ: 92936285Sbrian ipcp->peer_reject |= (1 << type); 9306059Samurai break; 9316059Samurai } 9326059Samurai break; 93328679Sbrian case TY_IPADDRS: /* RFC1172 */ 93438814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 93538814Sbrian memcpy(&dstipaddr.s_addr, cp + 6, 4); 93631962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 93736285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 9386059Samurai 93931034Sbrian switch (mode_type) { 9406059Samurai case MODE_REQ: 94136285Sbrian ipcp->peer_ip = ipaddr; 94236285Sbrian ipcp->my_ip = dstipaddr; 94336285Sbrian memcpy(dec->ackend, cp, length); 94436285Sbrian dec->ackend += length; 9456059Samurai break; 9466059Samurai case MODE_NAK: 94731962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff, 94836285Sbrian inet_ntoa(ipcp->my_ip)); 94936285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 95036285Sbrian ipcp->my_ip = ipaddr; 95136285Sbrian ipcp->peer_ip = dstipaddr; 9526059Samurai break; 9536059Samurai case MODE_REJ: 95436285Sbrian ipcp->peer_reject |= (1 << type); 9556059Samurai break; 9566059Samurai } 9576059Samurai break; 95818752Sjkh 95936285Sbrian case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ 96036285Sbrian case TY_SECONDARY_DNS: 96138814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 96236285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 96318752Sjkh 96431034Sbrian switch (mode_type) { 96518752Sjkh case MODE_REQ: 96636285Sbrian if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { 96736285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 96836285Sbrian memcpy(dec->rejend, cp, length); 96936285Sbrian dec->rejend += length; 97036285Sbrian break; 97136285Sbrian } 97236285Sbrian if (!gotdns) { 97336285Sbrian dns[0] = ipcp->cfg.ns.dns[0]; 97436285Sbrian dns[1] = ipcp->cfg.ns.dns[1]; 97536285Sbrian if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) 97636285Sbrian getdns(ipcp, dns); 97736285Sbrian gotdns = 1; 97836285Sbrian } 97936285Sbrian have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; 98028679Sbrian 98136285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 98218752Sjkh /* 98336285Sbrian * The client has got the DNS stuff wrong (first request) so 98428974Sbrian * we'll tell 'em how it is 98528679Sbrian */ 98636285Sbrian memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ 98736285Sbrian memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); 98836285Sbrian dec->nakend += length; 98936285Sbrian } else { 99036285Sbrian /* 99136285Sbrian * Otherwise they have it right (this time) so we send a ack packet 99236285Sbrian * back confirming it... end of story 99336285Sbrian */ 99436285Sbrian memcpy(dec->ackend, cp, length); 99536285Sbrian dec->ackend += length; 99636285Sbrian } 99718752Sjkh break; 99828679Sbrian case MODE_NAK: /* what does this mean?? */ 99936285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 100036285Sbrian gotdnsnak = 1; 100138814Sbrian memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4); 100236285Sbrian } 100318752Sjkh break; 100436285Sbrian case MODE_REJ: /* Can't do much, stop asking */ 100536285Sbrian ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); 100618752Sjkh break; 100718752Sjkh } 100818752Sjkh break; 100918752Sjkh 101036285Sbrian case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ 101118752Sjkh case TY_SECONDARY_NBNS: 101238814Sbrian memcpy(&ipaddr.s_addr, cp + 2, 4); 101336285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 101436285Sbrian 101531034Sbrian switch (mode_type) { 101618752Sjkh case MODE_REQ: 101736285Sbrian have_ip.s_addr = 101836285Sbrian ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; 101936285Sbrian 102036285Sbrian if (have_ip.s_addr == INADDR_ANY) { 102136285Sbrian log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); 102236285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 102336285Sbrian memcpy(dec->rejend, cp, length); 102436285Sbrian dec->rejend += length; 102518752Sjkh break; 102636285Sbrian } 102736285Sbrian 102836285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 102936285Sbrian memcpy(dec->nakend, cp, 2); 103036285Sbrian memcpy(dec->nakend+2, &have_ip.s_addr, length); 103136285Sbrian dec->nakend += length; 103236285Sbrian } else { 103336285Sbrian memcpy(dec->ackend, cp, length); 103436285Sbrian dec->ackend += length; 103536285Sbrian } 103618752Sjkh break; 103718752Sjkh case MODE_NAK: 103836285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 103918752Sjkh break; 104018752Sjkh case MODE_REJ: 104136285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 104218752Sjkh break; 104318752Sjkh } 104418752Sjkh break; 104518752Sjkh 10466059Samurai default: 104736285Sbrian if (mode_type != MODE_NOP) { 104836285Sbrian ipcp->my_reject |= (1 << type); 104936285Sbrian memcpy(dec->rejend, cp, length); 105036285Sbrian dec->rejend += length; 105136285Sbrian } 10526059Samurai break; 10536059Samurai } 10546059Samurai plen -= length; 10556059Samurai cp += length; 10566059Samurai } 105736285Sbrian 105836285Sbrian if (gotdnsnak) 105936285Sbrian if (!setdns(ipcp, dnsnak)) { 106036285Sbrian ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); 106136285Sbrian ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); 106236285Sbrian } 106336285Sbrian 106436285Sbrian if (mode_type != MODE_NOP) { 106536285Sbrian if (dec->rejend != dec->rej) { 106636285Sbrian /* rejects are preferred */ 106736285Sbrian dec->ackend = dec->ack; 106836285Sbrian dec->nakend = dec->nak; 106936285Sbrian } else if (dec->nakend != dec->nak) 107036285Sbrian /* then NAKs */ 107136285Sbrian dec->ackend = dec->ack; 107236285Sbrian } 10736059Samurai} 10746059Samurai 10756059Samuraivoid 107636285Sbrianipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp) 10776059Samurai{ 107836285Sbrian /* Got PROTO_IPCP from link */ 107936285Sbrian if (bundle_Phase(bundle) == PHASE_NETWORK) 108036285Sbrian fsm_Input(&ipcp->fsm, bp); 108136285Sbrian else { 108236285Sbrian if (bundle_Phase(bundle) < PHASE_NETWORK) 108336285Sbrian log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", 108436285Sbrian ipcp->fsm.link->name, bundle_PhaseName(bundle)); 108536285Sbrian mbuf_Free(bp); 108636285Sbrian } 10876059Samurai} 108832267Sbrian 108932267Sbrianint 109036285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 109132267Sbrian{ 109236285Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 109336285Sbrian 109436285Sbrian /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 109536285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 109636285Sbrian iplist_reset(&ipcp->cfg.peer_list); 109732267Sbrian if (strpbrk(hisaddr, ",-")) { 109836285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); 109936285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 110036285Sbrian iplist_setrandpos(&ipcp->cfg.peer_list); 110136285Sbrian ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); 110236285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 110336285Sbrian log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); 110432267Sbrian return(0); 110532267Sbrian } 110636285Sbrian ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; 110736285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 110836285Sbrian ipcp->cfg.peer_range.width = 32; 110932267Sbrian } else { 111036285Sbrian log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); 111132267Sbrian return 0; 111232267Sbrian } 111336285Sbrian } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr, 111436285Sbrian &ipcp->cfg.peer_range.mask, 111536285Sbrian &ipcp->cfg.peer_range.width) != 0) { 111636285Sbrian ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; 111732267Sbrian 111836285Sbrian if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, 111936285Sbrian ipcp->cfg.peer_range.ipaddr, 0) < 0) { 112036285Sbrian ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY; 112136285Sbrian ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY; 112232267Sbrian return 0; 112332267Sbrian } 112432267Sbrian } else 112532267Sbrian return 0; 112632267Sbrian 112732267Sbrian return 1; 112832267Sbrian} 1129