ipcp.c revision 37200
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 * 2037200Sbrian * $Id: ipcp.c,v 1.60 1998/06/27 14:18:06 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 3637191Sbrian#ifndef NOALIAS 3737191Sbrian#include <alias.h> 3837191Sbrian#endif 3936285Sbrian#include <fcntl.h> 4036285Sbrian#include <resolv.h> 4132614Sbrian#include <stdlib.h> 4230715Sbrian#include <string.h> 4336285Sbrian#include <sys/errno.h> 4436285Sbrian#include <termios.h> 4530715Sbrian#include <unistd.h> 4630715Sbrian 4737009Sbrian#include "defs.h" 4831343Sbrian#include "command.h" 4930715Sbrian#include "mbuf.h" 5030715Sbrian#include "log.h" 5130715Sbrian#include "timer.h" 5229048Sbrian#include "fsm.h" 5329048Sbrian#include "lcpproto.h" 5429048Sbrian#include "lcp.h" 5531690Sbrian#include "iplist.h" 5636285Sbrian#include "throughput.h" 5736285Sbrian#include "slcompress.h" 5829048Sbrian#include "ipcp.h" 5936285Sbrian#include "filter.h" 6036285Sbrian#include "descriptor.h" 6130715Sbrian#include "vjcomp.h" 6236285Sbrian#include "lqr.h" 6336285Sbrian#include "hdlc.h" 6436285Sbrian#include "async.h" 6536285Sbrian#include "ccp.h" 6636285Sbrian#include "link.h" 6736285Sbrian#include "physical.h" 6836285Sbrian#include "mp.h" 6936285Sbrian#include "bundle.h" 7036285Sbrian#include "id.h" 7136285Sbrian#include "arp.h" 7236285Sbrian#include "systems.h" 7336285Sbrian#include "prompt.h" 7431690Sbrian#include "route.h" 756059Samurai 7636285Sbrian#undef REJECTED 7736285Sbrian#define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) 7836285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t') 7936285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.') 806059Samurai 8136285Sbrianstruct compreq { 8236285Sbrian u_short proto; 8336285Sbrian u_char slots; 8436285Sbrian u_char compcid; 8536285Sbrian}; 866059Samurai 8736285Sbrianstatic int IpcpLayerUp(struct fsm *); 8836285Sbrianstatic void IpcpLayerDown(struct fsm *); 8926516Sbrianstatic void IpcpLayerStart(struct fsm *); 9026516Sbrianstatic void IpcpLayerFinish(struct fsm *); 9126516Sbrianstatic void IpcpInitRestartCounter(struct fsm *); 9236285Sbrianstatic void IpcpSendConfigReq(struct fsm *); 9336285Sbrianstatic void IpcpSentTerminateReq(struct fsm *); 9436285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char); 9536285Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, int, int, 9636285Sbrian struct fsm_decode *); 976059Samurai 9836285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = { 996059Samurai IpcpLayerUp, 1006059Samurai IpcpLayerDown, 1016059Samurai IpcpLayerStart, 1026059Samurai IpcpLayerFinish, 1036059Samurai IpcpInitRestartCounter, 1046059Samurai IpcpSendConfigReq, 10536285Sbrian IpcpSentTerminateReq, 1066059Samurai IpcpSendTerminateAck, 1076059Samurai IpcpDecodeConfig, 10836285Sbrian fsm_NullRecvResetReq, 10936285Sbrian fsm_NullRecvResetAck 1106059Samurai}; 1116059Samurai 11231343Sbrianstatic const char *cftypes[] = { 11331171Sbrian /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 11431171Sbrian "???", 11531171Sbrian "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ 11631171Sbrian "COMPPROTO", /* 2: IP-Compression-Protocol */ 11731171Sbrian "IPADDR", /* 3: IP-Address */ 1186059Samurai}; 1196059Samurai 12031962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 12131171Sbrian 12231343Sbrianstatic const char *cftypes128[] = { 12331171Sbrian /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 12431171Sbrian "???", 12531171Sbrian "PRIDNS", /* 129: Primary DNS Server Address */ 12631171Sbrian "PRINBNS", /* 130: Primary NBNS Server Address */ 12731171Sbrian "SECDNS", /* 131: Secondary DNS Server Address */ 12831171Sbrian "SECNBNS", /* 132: Secondary NBNS Server Address */ 12931171Sbrian}; 13031171Sbrian 13131962Sbrian#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) 13231171Sbrian 13331272Sbrianvoid 13436285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n) 1356059Samurai{ 13636285Sbrian throughput_addin(&ipcp->throughput, n); 1376059Samurai} 1386059Samurai 13931272Sbrianvoid 14036285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n) 1416059Samurai{ 14236285Sbrian throughput_addout(&ipcp->throughput, n); 1436059Samurai} 1446059Samurai 14536285Sbrianstatic void 14636285Sbriangetdns(struct ipcp *ipcp, struct in_addr addr[2]) 1476059Samurai{ 14836285Sbrian FILE *fp; 1496059Samurai 15036285Sbrian addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 15136285Sbrian if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 15236285Sbrian char buf[LINE_LEN], *cp, *end; 15336285Sbrian int n; 15436285Sbrian 15536285Sbrian n = 0; 15636285Sbrian buf[sizeof buf - 1] = '\0'; 15736285Sbrian while (fgets(buf, sizeof buf - 1, fp)) { 15836285Sbrian if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) { 15936285Sbrian for (cp = buf + 11; issep(*cp); cp++) 16036285Sbrian ; 16136285Sbrian for (end = cp; isip(*end); end++) 16236285Sbrian ; 16336285Sbrian *end = '\0'; 16436285Sbrian if (inet_aton(cp, addr+n) && ++n == 2) 16536285Sbrian break; 16636285Sbrian } 16736285Sbrian } 16836285Sbrian if (n == 1) 16936285Sbrian addr[1] = addr[0]; 17036285Sbrian fclose(fp); 17132614Sbrian } 17236285Sbrian} 17329048Sbrian 17436285Sbrianstatic int 17536285Sbriansetdns(struct ipcp *ipcp, struct in_addr addr[2]) 17636285Sbrian{ 17736285Sbrian FILE *fp; 17836285Sbrian char wbuf[LINE_LEN + 54]; 17936285Sbrian int wlen; 18026516Sbrian 18136285Sbrian if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) { 18236285Sbrian struct in_addr old[2]; 18331272Sbrian 18436285Sbrian getdns(ipcp, old); 18536285Sbrian if (addr[0].s_addr == INADDR_ANY) 18636285Sbrian addr[0] = old[0]; 18736285Sbrian if (addr[1].s_addr == INADDR_ANY) 18836285Sbrian addr[1] = old[1]; 18936285Sbrian } 19036285Sbrian 19136285Sbrian if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) { 19236285Sbrian log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n", 19336285Sbrian _PATH_RESCONF); 19436285Sbrian return 0; 19536285Sbrian } 19636285Sbrian 19736285Sbrian wlen = 0; 19836285Sbrian if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 19936285Sbrian char buf[LINE_LEN]; 20036285Sbrian int len; 20136285Sbrian 20236285Sbrian buf[sizeof buf - 1] = '\0'; 20336285Sbrian while (fgets(buf, sizeof buf - 1, fp)) { 20436285Sbrian if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) { 20536285Sbrian len = strlen(buf); 20636285Sbrian if (len > sizeof wbuf - wlen) { 20736285Sbrian log_Printf(LogWARN, "%s: Can only cope with max file size %d\n", 20836285Sbrian _PATH_RESCONF, LINE_LEN); 20936285Sbrian fclose(fp); 21036285Sbrian return 0; 21136285Sbrian } 21236285Sbrian memcpy(wbuf + wlen, buf, len); 21336285Sbrian wlen += len; 21436285Sbrian } 21536285Sbrian } 21636285Sbrian fclose(fp); 21736285Sbrian } 21836285Sbrian 21936285Sbrian if (addr[0].s_addr != INADDR_ANY) { 22036285Sbrian snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 22136285Sbrian inet_ntoa(addr[0])); 22236285Sbrian log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11); 22336285Sbrian wlen += strlen(wbuf + wlen); 22436285Sbrian } 22536285Sbrian 22636285Sbrian if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) { 22736285Sbrian snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", 22836285Sbrian inet_ntoa(addr[1])); 22936285Sbrian log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11); 23036285Sbrian wlen += strlen(wbuf + wlen); 23136285Sbrian } 23236285Sbrian 23336285Sbrian if (wlen) { 23436285Sbrian int fd; 23536285Sbrian 23636285Sbrian if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) { 23736285Sbrian if (write(fd, wbuf, wlen) != wlen) { 23836285Sbrian log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno)); 23936285Sbrian close(fd); 24036285Sbrian return 0; 24136285Sbrian } 24236285Sbrian if (ftruncate(fd, wlen) == -1) { 24336285Sbrian log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno)); 24436285Sbrian close(fd); 24536285Sbrian return 0; 24636285Sbrian } 24736285Sbrian close(fd); 24836285Sbrian } else { 24936285Sbrian log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno)); 25036285Sbrian return 0; 25136285Sbrian } 25236285Sbrian } 25336285Sbrian 25436285Sbrian return 1; 2556059Samurai} 2566059Samurai 25736285Sbrianint 25836285Sbrianipcp_Show(struct cmdargs const *arg) 2596059Samurai{ 26036285Sbrian struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 2616059Samurai 26236285Sbrian prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, 26336285Sbrian State2Nam(ipcp->fsm.state)); 26436285Sbrian if (ipcp->fsm.state == ST_OPENED) { 26536285Sbrian prompt_Printf(arg->prompt, " His side: %s, %s\n", 26636285Sbrian inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); 26736285Sbrian prompt_Printf(arg->prompt, " My side: %s, %s\n", 26836285Sbrian inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); 2696059Samurai } 27036285Sbrian 27136285Sbrian if (ipcp->route) { 27236285Sbrian prompt_Printf(arg->prompt, "\n"); 27336285Sbrian route_ShowSticky(arg->prompt, ipcp->route); 27436285Sbrian } 27536285Sbrian 27636285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 27736285Sbrian prompt_Printf(arg->prompt, " My Address: %s/%d", 27836285Sbrian inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width); 27936285Sbrian 28036285Sbrian if (ipcp->cfg.HaveTriggerAddress) 28136285Sbrian prompt_Printf(arg->prompt, " (trigger with %s)", 28236285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 28336285Sbrian prompt_Printf(arg->prompt, "\n VJ compression: %s (%d slots %s slot " 28436285Sbrian "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), 28536285Sbrian ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); 28636285Sbrian 28736285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) 28836285Sbrian prompt_Printf(arg->prompt, " His Address: %s\n", 28936285Sbrian ipcp->cfg.peer_list.src); 29036285Sbrian else 29136285Sbrian prompt_Printf(arg->prompt, " His Address: %s/%d\n", 29236285Sbrian inet_ntoa(ipcp->cfg.peer_range.ipaddr), 29336285Sbrian ipcp->cfg.peer_range.width); 29436285Sbrian 29536285Sbrian prompt_Printf(arg->prompt, " DNS: %s, ", 29636285Sbrian inet_ntoa(ipcp->cfg.ns.dns[0])); 29736285Sbrian prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]), 29836285Sbrian command_ShowNegval(ipcp->cfg.ns.dns_neg)); 29936285Sbrian prompt_Printf(arg->prompt, " NetBIOS NS: %s, ", 30036285Sbrian inet_ntoa(ipcp->cfg.ns.nbns[0])); 30136285Sbrian prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1])); 30236285Sbrian 30336285Sbrian prompt_Printf(arg->prompt, "\n"); 30436285Sbrian throughput_disp(&ipcp->throughput, arg->prompt); 30536285Sbrian 30636285Sbrian return 0; 3076059Samurai} 3086059Samurai 30932614Sbrianint 31036285Sbrianipcp_vjset(struct cmdargs const *arg) 31132614Sbrian{ 31236285Sbrian if (arg->argc != arg->argn+2) 31332614Sbrian return -1; 31436285Sbrian if (!strcasecmp(arg->argv[arg->argn], "slots")) { 31532614Sbrian int slots; 31632614Sbrian 31736285Sbrian slots = atoi(arg->argv[arg->argn+1]); 31832614Sbrian if (slots < 4 || slots > 16) 31932614Sbrian return 1; 32036285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slots = slots; 32132614Sbrian return 0; 32236285Sbrian } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { 32336285Sbrian if (!strcasecmp(arg->argv[arg->argn+1], "on")) 32436285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; 32536285Sbrian else if (!strcasecmp(arg->argv[arg->argn+1], "off")) 32636285Sbrian arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; 32732614Sbrian else 32832614Sbrian return 2; 32932614Sbrian return 0; 33032614Sbrian } 33132614Sbrian return -1; 33232614Sbrian} 33332614Sbrian 33436285Sbrianvoid 33536285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, 33636285Sbrian const struct fsm_parent *parent) 33732614Sbrian{ 33836285Sbrian struct hostent *hp; 33936285Sbrian char name[MAXHOSTNAMELEN]; 34036285Sbrian static const char *timer_names[] = 34136285Sbrian {"IPCP restart", "IPCP openmode", "IPCP stopped"}; 34236285Sbrian 34336285Sbrian fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP, 34436285Sbrian bundle, l, parent, &ipcp_Callbacks, timer_names); 34536285Sbrian 34636285Sbrian ipcp->route = NULL; 34736285Sbrian ipcp->cfg.vj.slots = DEF_VJ_STATES; 34836285Sbrian ipcp->cfg.vj.slotcomp = 1; 34936285Sbrian memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 35036285Sbrian if (gethostname(name, sizeof name) == 0) { 35136285Sbrian hp = gethostbyname(name); 35236285Sbrian if (hp && hp->h_addrtype == AF_INET) { 35336285Sbrian memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); 35436285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 35536285Sbrian ipcp->cfg.peer_range.width = 32; 35636285Sbrian } 35732614Sbrian } 35836285Sbrian ipcp->cfg.netmask.s_addr = INADDR_ANY; 35936285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 36036285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, ""); 36136285Sbrian ipcp->cfg.HaveTriggerAddress = 0; 36236285Sbrian 36336285Sbrian ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY; 36436285Sbrian ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY; 36536285Sbrian ipcp->cfg.ns.dns_neg = 0; 36636285Sbrian ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; 36736285Sbrian ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; 36836285Sbrian 36936285Sbrian ipcp->cfg.fsmretry = DEF_FSMRETRY; 37036285Sbrian ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; 37136285Sbrian 37236285Sbrian memset(&ipcp->vj, '\0', sizeof ipcp->vj); 37336285Sbrian 37436285Sbrian ipcp->my_ifip.s_addr = INADDR_ANY; 37536285Sbrian ipcp->peer_ifip.s_addr = INADDR_ANY; 37636285Sbrian 37736285Sbrian throughput_init(&ipcp->throughput); 37836285Sbrian ipcp_Setup(ipcp); 37932614Sbrian} 38032614Sbrian 3816059Samuraivoid 38236285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l) 3836059Samurai{ 38436285Sbrian ipcp->fsm.link = l; 38536285Sbrian} 38636285Sbrian 38736285Sbrianvoid 38836285Sbrianipcp_Setup(struct ipcp *ipcp) 38936285Sbrian{ 39036285Sbrian int pos; 39136285Sbrian 39236285Sbrian ipcp->fsm.open_mode = 0; 39336285Sbrian ipcp->fsm.maxconfig = 10; 39436285Sbrian 39536285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 39636285Sbrian if (ipcp->my_ifip.s_addr != INADDR_ANY && 39736285Sbrian (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1) 39836285Sbrian ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos); 39936285Sbrian else 40036285Sbrian ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); 40136285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 40236285Sbrian ipcp->cfg.peer_range.width = 32; 4036059Samurai } 4049440Samurai 40536285Sbrian ipcp->heis1172 = 0; 40636285Sbrian 40736285Sbrian ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; 40836285Sbrian ipcp->peer_compproto = 0; 40936285Sbrian 41036285Sbrian if (ipcp->cfg.HaveTriggerAddress) { 41136285Sbrian /* 41236285Sbrian * Some implementations of PPP require that we send a 41336285Sbrian * *special* value as our address, even though the rfc specifies 41436285Sbrian * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 41536285Sbrian */ 41636285Sbrian ipcp->my_ip = ipcp->cfg.TriggerAddress; 41736285Sbrian log_Printf(LogIPCP, "Using trigger address %s\n", 41836285Sbrian inet_ntoa(ipcp->cfg.TriggerAddress)); 41936285Sbrian } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) == 42036285Sbrian (ipcp->cfg.my_range.ipaddr.s_addr & 42136285Sbrian ipcp->cfg.my_range.mask.s_addr)) 42236285Sbrian /* 42336285Sbrian * Otherwise, if we've been assigned an IP number before, we really 42436285Sbrian * want to keep the same IP number so that we can keep any existing 42536285Sbrian * connections that are bound to that IP. 42636285Sbrian */ 42736285Sbrian ipcp->my_ip = ipcp->my_ifip; 42836285Sbrian else 42936285Sbrian ipcp->my_ip = ipcp->cfg.my_range.ipaddr; 43036285Sbrian 43136285Sbrian if (IsEnabled(ipcp->cfg.vj.neg)) 43236285Sbrian ipcp->my_compproto = (PROTO_VJCOMP << 16) + 43336285Sbrian ((ipcp->cfg.vj.slots - 1) << 8) + 43436285Sbrian ipcp->cfg.vj.slotcomp; 43536285Sbrian else 43636285Sbrian ipcp->my_compproto = 0; 43736285Sbrian sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); 43836285Sbrian 43936285Sbrian ipcp->peer_reject = 0; 44036285Sbrian ipcp->my_reject = 0; 44136285Sbrian 44236285Sbrian throughput_stop(&ipcp->throughput); 44336285Sbrian throughput_init(&ipcp->throughput); 44436285Sbrian} 44536285Sbrian 44636285Sbrianstatic int 44736285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, 44836285Sbrian struct in_addr hisaddr, int silent) 44936285Sbrian{ 45036285Sbrian struct sockaddr_in *sock_in; 45136285Sbrian int s; 45237200Sbrian u_int32_t mask, addr; 45336285Sbrian struct ifaliasreq ifra; 45436285Sbrian 45536285Sbrian /* If given addresses are alreay set, then ignore this request */ 45636285Sbrian if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr && 45736285Sbrian bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr) 45836285Sbrian return 0; 45936285Sbrian 46036285Sbrian ipcp_CleanInterface(&bundle->ncp.ipcp); 46136285Sbrian 46236285Sbrian s = ID0socket(AF_INET, SOCK_DGRAM, 0); 46336285Sbrian if (s < 0) { 46437019Sbrian log_Printf(LogERROR, "SetIPaddress: socket(): %s\n", strerror(errno)); 46536285Sbrian return (-1); 4669440Samurai } 46736285Sbrian 46836285Sbrian memset(&ifra, '\0', sizeof ifra); 46936285Sbrian strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1); 47036285Sbrian ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 47136285Sbrian 47236285Sbrian /* Set interface address */ 47336285Sbrian sock_in = (struct sockaddr_in *)&ifra.ifra_addr; 47436285Sbrian sock_in->sin_family = AF_INET; 47536285Sbrian sock_in->sin_addr = myaddr; 47636285Sbrian sock_in->sin_len = sizeof *sock_in; 47736285Sbrian 47836285Sbrian /* Set destination address */ 47936285Sbrian sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr; 48036285Sbrian sock_in->sin_family = AF_INET; 48136285Sbrian sock_in->sin_addr = hisaddr; 48236285Sbrian sock_in->sin_len = sizeof *sock_in; 48336285Sbrian 48436285Sbrian addr = ntohl(myaddr.s_addr); 48536285Sbrian if (IN_CLASSA(addr)) 48636285Sbrian mask = IN_CLASSA_NET; 48736285Sbrian else if (IN_CLASSB(addr)) 48836285Sbrian mask = IN_CLASSB_NET; 4896059Samurai else 49036285Sbrian mask = IN_CLASSC_NET; 49136285Sbrian 49236285Sbrian /* if subnet mask is given, use it instead of class mask */ 49336285Sbrian if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY && 49436285Sbrian (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask) 49536285Sbrian mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr); 49636285Sbrian 49736285Sbrian sock_in = (struct sockaddr_in *)&ifra.ifra_mask; 49836285Sbrian sock_in->sin_family = AF_INET; 49936285Sbrian sock_in->sin_addr.s_addr = htonl(mask); 50036285Sbrian sock_in->sin_len = sizeof *sock_in; 50136285Sbrian 50236285Sbrian if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { 50336285Sbrian if (!silent) 50437019Sbrian log_Printf(LogERROR, "SetIPaddress: ioctl(SIOCAIFADDR): %s\n", 50536285Sbrian strerror(errno)); 50636285Sbrian close(s); 50736285Sbrian return (-1); 50836285Sbrian } 50936285Sbrian 51036285Sbrian if (Enabled(bundle, OPT_SROUTES)) 51136285Sbrian route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); 51236285Sbrian 51336285Sbrian bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr; 51436285Sbrian bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr; 51536285Sbrian 51636285Sbrian if (Enabled(bundle, OPT_PROXY)) 51736285Sbrian arp_SetProxy(bundle, bundle->ncp.ipcp.peer_ifip, s); 51836285Sbrian 51936285Sbrian close(s); 52036285Sbrian return (0); 5216059Samurai} 5226059Samurai 52336285Sbrianstatic struct in_addr 52436285SbrianChooseHisAddr(struct bundle *bundle, const struct in_addr gw) 52536285Sbrian{ 52636285Sbrian struct in_addr try; 52736285Sbrian int f; 52836285Sbrian 52936285Sbrian for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { 53036285Sbrian try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); 53136285Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n", 53236285Sbrian f, inet_ntoa(try)); 53336285Sbrian if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { 53436285Sbrian log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); 53536285Sbrian break; 53636285Sbrian } 53736285Sbrian } 53836285Sbrian 53936285Sbrian if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { 54036285Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 54136285Sbrian try.s_addr = INADDR_ANY; 54236285Sbrian } 54336285Sbrian 54436285Sbrian return try; 54536285Sbrian} 54636285Sbrian 5476059Samuraistatic void 54828679SbrianIpcpInitRestartCounter(struct fsm * fp) 5496059Samurai{ 55036285Sbrian /* Set fsm timer load */ 55136285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 55236285Sbrian 55336285Sbrian fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS; 5546059Samurai fp->restart = 5; 5556059Samurai} 5566059Samurai 5576059Samuraistatic void 55836285SbrianIpcpSendConfigReq(struct fsm *fp) 5596059Samurai{ 56036285Sbrian /* Send config REQ please */ 56136285Sbrian struct physical *p = link2physical(fp->link); 56236285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 56336285Sbrian u_char buff[24]; 56436285Sbrian struct lcp_opt *o; 5656059Samurai 56636285Sbrian o = (struct lcp_opt *)buff; 56736285Sbrian 56836285Sbrian if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 56936285Sbrian *(u_int32_t *)o->data = ipcp->my_ip.s_addr; 57036285Sbrian INC_LCP_OPT(TY_IPADDR, 6, o); 57131514Sbrian } 57231514Sbrian 57336285Sbrian if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 57436285Sbrian if (ipcp->heis1172) { 57536285Sbrian *(u_short *)o->data = htons(PROTO_VJCOMP); 57636285Sbrian INC_LCP_OPT(TY_COMPPROTO, 4, o); 57731514Sbrian } else { 57837200Sbrian *(u_int32_t *)o->data = htonl(ipcp->my_compproto); 57936285Sbrian INC_LCP_OPT(TY_COMPPROTO, 6, o); 58031514Sbrian } 5816059Samurai } 58236285Sbrian 58336285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg) && 58436285Sbrian !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && 58536285Sbrian !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { 58636285Sbrian struct in_addr dns[2]; 58736285Sbrian getdns(ipcp, dns); 58836285Sbrian *(u_int32_t *)o->data = dns[0].s_addr; 58936285Sbrian INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); 59036285Sbrian *(u_int32_t *)o->data = dns[1].s_addr; 59136285Sbrian INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); 59236285Sbrian } 59336285Sbrian 59436285Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff); 5956059Samurai} 5966059Samurai 5976059Samuraistatic void 59836285SbrianIpcpSentTerminateReq(struct fsm * fp) 5996059Samurai{ 60036285Sbrian /* Term REQ just sent by FSM */ 6016059Samurai} 6026059Samurai 6036059Samuraistatic void 60436285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id) 6056059Samurai{ 60636285Sbrian /* Send Term ACK please */ 60736285Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0); 6086059Samurai} 6096059Samurai 6106059Samuraistatic void 61137160SbrianIpcpLayerStart(struct fsm *fp) 6126059Samurai{ 61336285Sbrian /* We're about to start up ! */ 61437160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 61537160Sbrian 61636285Sbrian log_Printf(LogIPCP, "%s: IpcpLayerStart.\n", fp->link->name); 61737160Sbrian throughput_start(&ipcp->throughput, "IPCP throughput", 61837160Sbrian Enabled(fp->bundle, OPT_THROUGHPUT)); 61936285Sbrian 62036465Sbrian /* This is where we should be setting up the interface in AUTO mode */ 6216059Samurai} 6226059Samurai 6236059Samuraistatic void 62436285SbrianIpcpLayerFinish(struct fsm *fp) 6256059Samurai{ 62636285Sbrian /* We're now down */ 62737160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 62837160Sbrian 62936285Sbrian log_Printf(LogIPCP, "%s: IpcpLayerFinish.\n", fp->link->name); 63037160Sbrian throughput_stop(&ipcp->throughput); 63137160Sbrian throughput_log(&ipcp->throughput, LogIPCP, NULL); 6326059Samurai} 6336059Samurai 63436285Sbrianvoid 63536285Sbrianipcp_CleanInterface(struct ipcp *ipcp) 6366059Samurai{ 63736285Sbrian struct ifaliasreq ifra; 63836285Sbrian struct sockaddr_in *me, *peer; 63936285Sbrian int s; 64036285Sbrian 64136285Sbrian s = ID0socket(AF_INET, SOCK_DGRAM, 0); 64236285Sbrian if (s < 0) { 64336285Sbrian log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno)); 64436285Sbrian return; 64536285Sbrian } 64636285Sbrian 64736285Sbrian route_Clean(ipcp->fsm.bundle, ipcp->route); 64836285Sbrian 64936285Sbrian if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) 65036285Sbrian arp_ClearProxy(ipcp->fsm.bundle, ipcp->peer_ifip, s); 65136285Sbrian 65236285Sbrian if (ipcp->my_ifip.s_addr != INADDR_ANY || 65336285Sbrian ipcp->peer_ifip.s_addr != INADDR_ANY) { 65436285Sbrian memset(&ifra, '\0', sizeof ifra); 65536285Sbrian strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifp.Name, 65636285Sbrian sizeof ifra.ifra_name - 1); 65736285Sbrian ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 65836285Sbrian me = (struct sockaddr_in *)&ifra.ifra_addr; 65936285Sbrian peer = (struct sockaddr_in *)&ifra.ifra_broadaddr; 66036285Sbrian me->sin_family = peer->sin_family = AF_INET; 66136285Sbrian me->sin_len = peer->sin_len = sizeof(struct sockaddr_in); 66236285Sbrian me->sin_addr = ipcp->my_ifip; 66336285Sbrian peer->sin_addr = ipcp->peer_ifip; 66436285Sbrian if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) 66536285Sbrian log_Printf(LogERROR, "ipcp_CleanInterface: ioctl(SIOCDIFADDR): %s\n", 66636285Sbrian strerror(errno)); 66736285Sbrian ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY; 66836285Sbrian } 66936285Sbrian 67036285Sbrian close(s); 6716059Samurai} 6726059Samurai 6736059Samuraistatic void 67436285SbrianIpcpLayerDown(struct fsm *fp) 6756059Samurai{ 67636285Sbrian /* About to come down */ 67736285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 67836285Sbrian const char *s; 6796059Samurai 68036285Sbrian s = inet_ntoa(ipcp->peer_ifip); 68136285Sbrian log_Printf(LogIPCP, "%s: IpcpLayerDown: %s\n", fp->link->name, s); 68230187Sbrian 68336285Sbrian /* 68436285Sbrian * XXX this stuff should really live in the FSM. Our config should 68536285Sbrian * associate executable sections in files with events. 68636285Sbrian */ 68737008Sbrian if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) { 68836285Sbrian if (bundle_GetLabel(fp->bundle)) { 68936285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 69037008Sbrian LINKDOWNFILE, NULL, NULL) < 0) 69137008Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 69236285Sbrian } else 69337008Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 69436285Sbrian } 69530187Sbrian 69636928Sbrian if (!(ipcp->fsm.bundle->phys_type.all & PHYS_AUTO)) 69736285Sbrian ipcp_CleanInterface(ipcp); 69837160Sbrian 69937160Sbrian ipcp_Setup(ipcp); 70036285Sbrian} 70136285Sbrian 70236285Sbrianint 70336285Sbrianipcp_InterfaceUp(struct ipcp *ipcp) 70436285Sbrian{ 70536285Sbrian if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { 70637019Sbrian log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n"); 70736285Sbrian return 0; 70825630Sbrian } 70936285Sbrian 71031343Sbrian#ifndef NOALIAS 71137191Sbrian if (ipcp->fsm.bundle->AliasEnabled) 71237191Sbrian PacketAliasSetAddress(ipcp->my_ip); 71331343Sbrian#endif 71436285Sbrian 71536285Sbrian return 1; 7166059Samurai} 7176059Samurai 71836285Sbrianstatic int 71936285SbrianIpcpLayerUp(struct fsm *fp) 7206059Samurai{ 72136285Sbrian /* We're now up */ 72236285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 72336285Sbrian char tbuff[100]; 7246059Samurai 72536285Sbrian log_Printf(LogIPCP, "%s: IpcpLayerUp.\n", fp->link->name); 72636285Sbrian snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip)); 72736285Sbrian log_Printf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip)); 72836285Sbrian 72936285Sbrian if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 73036285Sbrian sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); 73136285Sbrian 73236285Sbrian if (!ipcp_InterfaceUp(ipcp)) 73336285Sbrian return 0; 73436285Sbrian 73536285Sbrian /* 73636285Sbrian * XXX this stuff should really live in the FSM. Our config should 73736285Sbrian * associate executable sections in files with events. 73836285Sbrian */ 73937008Sbrian if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, 74037008Sbrian NULL, NULL) < 0) { 74136285Sbrian if (bundle_GetLabel(fp->bundle)) { 74236285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 74337008Sbrian LINKUPFILE, NULL, NULL) < 0) 74437008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 74536285Sbrian } else 74637008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 74736285Sbrian } 74836285Sbrian 74936314Sbrian log_DisplayPrompts(); 75036285Sbrian return 1; 7516059Samurai} 7526059Samurai 7536059Samuraistatic int 75436285SbrianAcceptableAddr(struct in_range *prange, struct in_addr ipaddr) 7556059Samurai{ 75636285Sbrian /* Is the given IP in the given range ? */ 75725661Sbrian return (prange->ipaddr.s_addr & prange->mask.s_addr) == 75828679Sbrian (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 7596059Samurai} 7606059Samurai 7616059Samuraistatic void 76236285SbrianIpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type, 76336285Sbrian struct fsm_decode *dec) 7646059Samurai{ 76536285Sbrian /* Deal with incoming PROTO_IPCP */ 76636285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 7676735Samurai int type, length; 76836285Sbrian u_int32_t compproto; 7696059Samurai struct compreq *pcomp; 77036285Sbrian struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; 77136285Sbrian char tbuff[100], tbuff2[100]; 77236285Sbrian int gotdns, gotdnsnak; 7736059Samurai 77436285Sbrian gotdns = 0; 77536285Sbrian gotdnsnak = 0; 77636285Sbrian dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; 7776059Samurai 7786059Samurai while (plen >= sizeof(struct fsmconfig)) { 7796059Samurai type = *cp; 7806059Samurai length = cp[1]; 78136285Sbrian 78236285Sbrian if (length == 0) { 78336285Sbrian log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); 78436285Sbrian break; 78536285Sbrian } 78636285Sbrian 78731171Sbrian if (type < NCFTYPES) 78831962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); 78931171Sbrian else if (type > 128 && type < 128 + NCFTYPES128) 79031962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); 7916059Samurai else 79231962Sbrian snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); 7936059Samurai 7946059Samurai switch (type) { 7956059Samurai case TY_IPADDR: /* RFC1332 */ 79636285Sbrian ipaddr.s_addr = *(u_int32_t *)(cp + 2); 79736285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 7986059Samurai 79931034Sbrian switch (mode_type) { 8006059Samurai case MODE_REQ: 80136285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 80231850Sbrian if (ipaddr.s_addr == INADDR_ANY || 80336285Sbrian iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || 80436285Sbrian ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, 80536285Sbrian ipaddr, 1)) { 80636285Sbrian log_Printf(LogIPCP, "%s: Address invalid or already in use\n", 80731690Sbrian inet_ntoa(ipaddr)); 80836285Sbrian if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0) 80936285Sbrian /* 81036285Sbrian * If we've already got a valid address configured for the peer 81136465Sbrian * (in AUTO mode), try NAKing with that so that we don't 81236285Sbrian * have to upset things too much. 81336285Sbrian */ 81436285Sbrian ipcp->peer_ip = ipcp->peer_ifip; 81536285Sbrian else 81636285Sbrian /* Just pick an IP number from our list */ 81736285Sbrian ipcp->peer_ip = ChooseHisAddr 81836285Sbrian (fp->bundle, ipcp->cfg.my_range.ipaddr); 81936285Sbrian 82036285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 82136285Sbrian memcpy(dec->rejend, cp, length); 82236285Sbrian dec->rejend += length; 82331690Sbrian } else { 82436285Sbrian memcpy(dec->nakend, cp, 2); 82536285Sbrian memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); 82636285Sbrian dec->nakend += length; 82731690Sbrian } 82831690Sbrian break; 82931690Sbrian } 83036285Sbrian } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { 83128679Sbrian /* 83236285Sbrian * If destination address is not acceptable, NAK with what we 83328679Sbrian * want to use. 83428679Sbrian */ 83536285Sbrian memcpy(dec->nakend, cp, 2); 83636285Sbrian if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) == 83736285Sbrian (ipcp->cfg.peer_range.ipaddr.s_addr & 83836285Sbrian ipcp->cfg.peer_range.mask.s_addr)) 83936285Sbrian /* We prefer the already-configured address */ 84036285Sbrian memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2); 84136285Sbrian else 84236285Sbrian memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); 84336285Sbrian dec->nakend += length; 84428679Sbrian break; 8456059Samurai } 84636285Sbrian ipcp->peer_ip = ipaddr; 84736285Sbrian memcpy(dec->ackend, cp, length); 84836285Sbrian dec->ackend += length; 8496059Samurai break; 8506059Samurai case MODE_NAK: 85136285Sbrian if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { 85231690Sbrian /* Use address suggested by peer */ 85331962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 85436285Sbrian inet_ntoa(ipcp->my_ip)); 85536285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 85636285Sbrian ipcp->my_ip = ipaddr; 85731690Sbrian } else { 85836285Sbrian log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, 85936285Sbrian "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 86036285Sbrian fsm_Close(&ipcp->fsm); 8616059Samurai } 8626059Samurai break; 8636059Samurai case MODE_REJ: 86436285Sbrian ipcp->peer_reject |= (1 << type); 8656059Samurai break; 8666059Samurai } 8676059Samurai break; 8686059Samurai case TY_COMPPROTO: 86936285Sbrian compproto = htonl(*(u_int32_t *)(cp + 2)); 87036285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 8716059Samurai 87231034Sbrian switch (mode_type) { 8736059Samurai case MODE_REQ: 87436285Sbrian if (!IsAccepted(ipcp->cfg.vj.neg)) { 87536285Sbrian memcpy(dec->rejend, cp, length); 87636285Sbrian dec->rejend += length; 8776059Samurai } else { 87828679Sbrian pcomp = (struct compreq *) (cp + 2); 8796059Samurai switch (length) { 88028679Sbrian case 4: /* RFC1172 */ 8816059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 88236285Sbrian log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); 88336285Sbrian ipcp->heis1172 = 1; 88436285Sbrian ipcp->peer_compproto = compproto; 88536285Sbrian memcpy(dec->ackend, cp, length); 88636285Sbrian dec->ackend += length; 8876059Samurai } else { 88836285Sbrian memcpy(dec->nakend, cp, 2); 8896059Samurai pcomp->proto = htons(PROTO_VJCOMP); 89036285Sbrian memcpy(dec->nakend+2, &pcomp, 2); 89136285Sbrian dec->nakend += length; 8926059Samurai } 8936059Samurai break; 89428679Sbrian case 6: /* RFC1332 */ 8956059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP 89636285Sbrian && pcomp->slots <= MAX_VJ_STATES 89736285Sbrian && pcomp->slots >= MIN_VJ_STATES) { 89836285Sbrian ipcp->peer_compproto = compproto; 89936285Sbrian ipcp->heis1172 = 0; 90036285Sbrian memcpy(dec->ackend, cp, length); 90136285Sbrian dec->ackend += length; 9026059Samurai } else { 90336285Sbrian memcpy(dec->nakend, cp, 2); 9046059Samurai pcomp->proto = htons(PROTO_VJCOMP); 90536285Sbrian pcomp->slots = DEF_VJ_STATES; 9066059Samurai pcomp->compcid = 0; 90736285Sbrian memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 90836285Sbrian dec->nakend += length; 9096059Samurai } 9106059Samurai break; 9116059Samurai default: 91236285Sbrian memcpy(dec->rejend, cp, length); 91336285Sbrian dec->rejend += length; 9146059Samurai break; 9156059Samurai } 9166059Samurai } 9176059Samurai break; 9186059Samurai case MODE_NAK: 91936285Sbrian log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 92036285Sbrian tbuff, ipcp->my_compproto, compproto); 92136285Sbrian ipcp->my_compproto = compproto; 9226059Samurai break; 9236059Samurai case MODE_REJ: 92436285Sbrian ipcp->peer_reject |= (1 << type); 9256059Samurai break; 9266059Samurai } 9276059Samurai break; 92828679Sbrian case TY_IPADDRS: /* RFC1172 */ 92936285Sbrian ipaddr.s_addr = *(u_int32_t *)(cp + 2); 93036285Sbrian dstipaddr.s_addr = *(u_int32_t *)(cp + 6); 93131962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 93236285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 9336059Samurai 93431034Sbrian switch (mode_type) { 9356059Samurai case MODE_REQ: 93636285Sbrian ipcp->peer_ip = ipaddr; 93736285Sbrian ipcp->my_ip = dstipaddr; 93836285Sbrian memcpy(dec->ackend, cp, length); 93936285Sbrian dec->ackend += length; 9406059Samurai break; 9416059Samurai case MODE_NAK: 94231962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff, 94336285Sbrian inet_ntoa(ipcp->my_ip)); 94436285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 94536285Sbrian ipcp->my_ip = ipaddr; 94636285Sbrian ipcp->peer_ip = dstipaddr; 9476059Samurai break; 9486059Samurai case MODE_REJ: 94936285Sbrian ipcp->peer_reject |= (1 << type); 9506059Samurai break; 9516059Samurai } 9526059Samurai break; 95318752Sjkh 95436285Sbrian case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ 95536285Sbrian case TY_SECONDARY_DNS: 95636285Sbrian ipaddr.s_addr = *(u_int32_t *)(cp + 2); 95736285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 95818752Sjkh 95931034Sbrian switch (mode_type) { 96018752Sjkh case MODE_REQ: 96136285Sbrian if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { 96236285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 96336285Sbrian memcpy(dec->rejend, cp, length); 96436285Sbrian dec->rejend += length; 96536285Sbrian break; 96636285Sbrian } 96736285Sbrian if (!gotdns) { 96836285Sbrian dns[0] = ipcp->cfg.ns.dns[0]; 96936285Sbrian dns[1] = ipcp->cfg.ns.dns[1]; 97036285Sbrian if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) 97136285Sbrian getdns(ipcp, dns); 97236285Sbrian gotdns = 1; 97336285Sbrian } 97436285Sbrian have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; 97528679Sbrian 97636285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 97718752Sjkh /* 97836285Sbrian * The client has got the DNS stuff wrong (first request) so 97928974Sbrian * we'll tell 'em how it is 98028679Sbrian */ 98136285Sbrian memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ 98236285Sbrian memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); 98336285Sbrian dec->nakend += length; 98436285Sbrian } else { 98536285Sbrian /* 98636285Sbrian * Otherwise they have it right (this time) so we send a ack packet 98736285Sbrian * back confirming it... end of story 98836285Sbrian */ 98936285Sbrian memcpy(dec->ackend, cp, length); 99036285Sbrian dec->ackend += length; 99136285Sbrian } 99218752Sjkh break; 99328679Sbrian case MODE_NAK: /* what does this mean?? */ 99436285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 99536285Sbrian gotdnsnak = 1; 99636285Sbrian dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr = 99736285Sbrian *(u_int32_t *)(cp + 2); 99836285Sbrian } 99918752Sjkh break; 100036285Sbrian case MODE_REJ: /* Can't do much, stop asking */ 100136285Sbrian ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); 100218752Sjkh break; 100318752Sjkh } 100418752Sjkh break; 100518752Sjkh 100636285Sbrian case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ 100718752Sjkh case TY_SECONDARY_NBNS: 100836285Sbrian ipaddr.s_addr = *(u_int32_t *)(cp + 2); 100936285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 101036285Sbrian 101131034Sbrian switch (mode_type) { 101218752Sjkh case MODE_REQ: 101336285Sbrian have_ip.s_addr = 101436285Sbrian ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; 101536285Sbrian 101636285Sbrian if (have_ip.s_addr == INADDR_ANY) { 101736285Sbrian log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); 101836285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 101936285Sbrian memcpy(dec->rejend, cp, length); 102036285Sbrian dec->rejend += length; 102118752Sjkh break; 102236285Sbrian } 102336285Sbrian 102436285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 102536285Sbrian memcpy(dec->nakend, cp, 2); 102636285Sbrian memcpy(dec->nakend+2, &have_ip.s_addr, length); 102736285Sbrian dec->nakend += length; 102836285Sbrian } else { 102936285Sbrian memcpy(dec->ackend, cp, length); 103036285Sbrian dec->ackend += length; 103136285Sbrian } 103218752Sjkh break; 103318752Sjkh case MODE_NAK: 103436285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 103518752Sjkh break; 103618752Sjkh case MODE_REJ: 103736285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 103818752Sjkh break; 103918752Sjkh } 104018752Sjkh break; 104118752Sjkh 10426059Samurai default: 104336285Sbrian if (mode_type != MODE_NOP) { 104436285Sbrian ipcp->my_reject |= (1 << type); 104536285Sbrian memcpy(dec->rejend, cp, length); 104636285Sbrian dec->rejend += length; 104736285Sbrian } 10486059Samurai break; 10496059Samurai } 10506059Samurai plen -= length; 10516059Samurai cp += length; 10526059Samurai } 105336285Sbrian 105436285Sbrian if (gotdnsnak) 105536285Sbrian if (!setdns(ipcp, dnsnak)) { 105636285Sbrian ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); 105736285Sbrian ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); 105836285Sbrian } 105936285Sbrian 106036285Sbrian if (mode_type != MODE_NOP) { 106136285Sbrian if (dec->rejend != dec->rej) { 106236285Sbrian /* rejects are preferred */ 106336285Sbrian dec->ackend = dec->ack; 106436285Sbrian dec->nakend = dec->nak; 106536285Sbrian } else if (dec->nakend != dec->nak) 106636285Sbrian /* then NAKs */ 106736285Sbrian dec->ackend = dec->ack; 106836285Sbrian } 10696059Samurai} 10706059Samurai 10716059Samuraivoid 107236285Sbrianipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp) 10736059Samurai{ 107436285Sbrian /* Got PROTO_IPCP from link */ 107536285Sbrian if (bundle_Phase(bundle) == PHASE_NETWORK) 107636285Sbrian fsm_Input(&ipcp->fsm, bp); 107736285Sbrian else { 107836285Sbrian if (bundle_Phase(bundle) < PHASE_NETWORK) 107936285Sbrian log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", 108036285Sbrian ipcp->fsm.link->name, bundle_PhaseName(bundle)); 108136285Sbrian mbuf_Free(bp); 108236285Sbrian } 10836059Samurai} 108432267Sbrian 108532267Sbrianint 108636285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 108732267Sbrian{ 108836285Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 108936285Sbrian 109036285Sbrian /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 109136285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 109236285Sbrian iplist_reset(&ipcp->cfg.peer_list); 109332267Sbrian if (strpbrk(hisaddr, ",-")) { 109436285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); 109536285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 109636285Sbrian iplist_setrandpos(&ipcp->cfg.peer_list); 109736285Sbrian ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); 109836285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 109936285Sbrian log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); 110032267Sbrian return(0); 110132267Sbrian } 110236285Sbrian ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; 110336285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 110436285Sbrian ipcp->cfg.peer_range.width = 32; 110532267Sbrian } else { 110636285Sbrian log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); 110732267Sbrian return 0; 110832267Sbrian } 110936285Sbrian } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr, 111036285Sbrian &ipcp->cfg.peer_range.mask, 111136285Sbrian &ipcp->cfg.peer_range.width) != 0) { 111236285Sbrian ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; 111332267Sbrian 111436285Sbrian if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, 111536285Sbrian ipcp->cfg.peer_range.ipaddr, 0) < 0) { 111636285Sbrian ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY; 111736285Sbrian ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY; 111832267Sbrian return 0; 111932267Sbrian } 112032267Sbrian } else 112132267Sbrian return 0; 112232267Sbrian 112332267Sbrian return 1; 112432267Sbrian} 1125