ipcp.c revision 38174
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 * 2038174Sbrian * $Id: ipcp.c,v 1.62 1998/06/27 23:48:45 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 44336285Sbrianstatic int 44436285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, 44536285Sbrian struct in_addr hisaddr, int silent) 44636285Sbrian{ 44736285Sbrian struct sockaddr_in *sock_in; 44836285Sbrian int s; 44937200Sbrian u_int32_t mask, addr; 45036285Sbrian struct ifaliasreq ifra; 45136285Sbrian 45236285Sbrian /* If given addresses are alreay set, then ignore this request */ 45336285Sbrian if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr && 45436285Sbrian bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr) 45536285Sbrian return 0; 45636285Sbrian 45736285Sbrian ipcp_CleanInterface(&bundle->ncp.ipcp); 45836285Sbrian 45936285Sbrian s = ID0socket(AF_INET, SOCK_DGRAM, 0); 46036285Sbrian if (s < 0) { 46137019Sbrian log_Printf(LogERROR, "SetIPaddress: socket(): %s\n", strerror(errno)); 46236285Sbrian return (-1); 4639440Samurai } 46436285Sbrian 46536285Sbrian memset(&ifra, '\0', sizeof ifra); 46636285Sbrian strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1); 46736285Sbrian ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 46836285Sbrian 46936285Sbrian /* Set interface address */ 47036285Sbrian sock_in = (struct sockaddr_in *)&ifra.ifra_addr; 47136285Sbrian sock_in->sin_family = AF_INET; 47236285Sbrian sock_in->sin_addr = myaddr; 47336285Sbrian sock_in->sin_len = sizeof *sock_in; 47436285Sbrian 47536285Sbrian /* Set destination address */ 47636285Sbrian sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr; 47736285Sbrian sock_in->sin_family = AF_INET; 47836285Sbrian sock_in->sin_addr = hisaddr; 47936285Sbrian sock_in->sin_len = sizeof *sock_in; 48036285Sbrian 48136285Sbrian addr = ntohl(myaddr.s_addr); 48236285Sbrian if (IN_CLASSA(addr)) 48336285Sbrian mask = IN_CLASSA_NET; 48436285Sbrian else if (IN_CLASSB(addr)) 48536285Sbrian mask = IN_CLASSB_NET; 4866059Samurai else 48736285Sbrian mask = IN_CLASSC_NET; 48836285Sbrian 48936285Sbrian /* if subnet mask is given, use it instead of class mask */ 49036285Sbrian if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY && 49136285Sbrian (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask) 49236285Sbrian mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr); 49336285Sbrian 49436285Sbrian sock_in = (struct sockaddr_in *)&ifra.ifra_mask; 49536285Sbrian sock_in->sin_family = AF_INET; 49636285Sbrian sock_in->sin_addr.s_addr = htonl(mask); 49736285Sbrian sock_in->sin_len = sizeof *sock_in; 49836285Sbrian 49936285Sbrian if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { 50036285Sbrian if (!silent) 50137019Sbrian log_Printf(LogERROR, "SetIPaddress: ioctl(SIOCAIFADDR): %s\n", 50236285Sbrian strerror(errno)); 50336285Sbrian close(s); 50436285Sbrian return (-1); 50536285Sbrian } 50636285Sbrian 50736285Sbrian if (Enabled(bundle, OPT_SROUTES)) 50836285Sbrian route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); 50936285Sbrian 51036285Sbrian bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr; 51136285Sbrian bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr; 51236285Sbrian 51336285Sbrian if (Enabled(bundle, OPT_PROXY)) 51436285Sbrian arp_SetProxy(bundle, bundle->ncp.ipcp.peer_ifip, s); 51536285Sbrian 51636285Sbrian close(s); 51736285Sbrian return (0); 5186059Samurai} 5196059Samurai 52036285Sbrianstatic struct in_addr 52136285SbrianChooseHisAddr(struct bundle *bundle, const struct in_addr gw) 52236285Sbrian{ 52336285Sbrian struct in_addr try; 52437210Sbrian u_long f; 52536285Sbrian 52636285Sbrian for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { 52736285Sbrian try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); 52837210Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n", 52936285Sbrian f, inet_ntoa(try)); 53036285Sbrian if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { 53136285Sbrian log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); 53236285Sbrian break; 53336285Sbrian } 53436285Sbrian } 53536285Sbrian 53636285Sbrian if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { 53736285Sbrian log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 53836285Sbrian try.s_addr = INADDR_ANY; 53936285Sbrian } 54036285Sbrian 54136285Sbrian return try; 54236285Sbrian} 54336285Sbrian 5446059Samuraistatic void 54528679SbrianIpcpInitRestartCounter(struct fsm * fp) 5466059Samurai{ 54736285Sbrian /* Set fsm timer load */ 54836285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 54936285Sbrian 55036285Sbrian fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS; 55138174Sbrian fp->restart = DEF_REQs; 5526059Samurai} 5536059Samurai 5546059Samuraistatic void 55536285SbrianIpcpSendConfigReq(struct fsm *fp) 5566059Samurai{ 55736285Sbrian /* Send config REQ please */ 55836285Sbrian struct physical *p = link2physical(fp->link); 55936285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 56036285Sbrian u_char buff[24]; 56136285Sbrian struct lcp_opt *o; 5626059Samurai 56336285Sbrian o = (struct lcp_opt *)buff; 56436285Sbrian 56536285Sbrian if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 56636285Sbrian *(u_int32_t *)o->data = ipcp->my_ip.s_addr; 56736285Sbrian INC_LCP_OPT(TY_IPADDR, 6, o); 56831514Sbrian } 56931514Sbrian 57036285Sbrian if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 57136285Sbrian if (ipcp->heis1172) { 57237210Sbrian *(u_int32_t *)o->data = htons(PROTO_VJCOMP); 57336285Sbrian INC_LCP_OPT(TY_COMPPROTO, 4, o); 57431514Sbrian } else { 57537200Sbrian *(u_int32_t *)o->data = htonl(ipcp->my_compproto); 57636285Sbrian INC_LCP_OPT(TY_COMPPROTO, 6, o); 57731514Sbrian } 5786059Samurai } 57936285Sbrian 58036285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg) && 58136285Sbrian !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && 58236285Sbrian !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { 58336285Sbrian struct in_addr dns[2]; 58436285Sbrian getdns(ipcp, dns); 58536285Sbrian *(u_int32_t *)o->data = dns[0].s_addr; 58636285Sbrian INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); 58736285Sbrian *(u_int32_t *)o->data = dns[1].s_addr; 58836285Sbrian INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); 58936285Sbrian } 59036285Sbrian 59136285Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff); 5926059Samurai} 5936059Samurai 5946059Samuraistatic void 59536285SbrianIpcpSentTerminateReq(struct fsm * fp) 5966059Samurai{ 59736285Sbrian /* Term REQ just sent by FSM */ 5986059Samurai} 5996059Samurai 6006059Samuraistatic void 60136285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id) 6026059Samurai{ 60336285Sbrian /* Send Term ACK please */ 60436285Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0); 6056059Samurai} 6066059Samurai 6076059Samuraistatic void 60837160SbrianIpcpLayerStart(struct fsm *fp) 6096059Samurai{ 61036285Sbrian /* We're about to start up ! */ 61137160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 61237160Sbrian 61337210Sbrian log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name); 61437160Sbrian throughput_start(&ipcp->throughput, "IPCP throughput", 61537160Sbrian Enabled(fp->bundle, OPT_THROUGHPUT)); 61636285Sbrian 61736465Sbrian /* This is where we should be setting up the interface in AUTO mode */ 6186059Samurai} 6196059Samurai 6206059Samuraistatic void 62136285SbrianIpcpLayerFinish(struct fsm *fp) 6226059Samurai{ 62336285Sbrian /* We're now down */ 62437160Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 62537160Sbrian 62637210Sbrian log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name); 62737160Sbrian throughput_stop(&ipcp->throughput); 62837160Sbrian throughput_log(&ipcp->throughput, LogIPCP, NULL); 6296059Samurai} 6306059Samurai 63136285Sbrianvoid 63236285Sbrianipcp_CleanInterface(struct ipcp *ipcp) 6336059Samurai{ 63436285Sbrian struct ifaliasreq ifra; 63536285Sbrian struct sockaddr_in *me, *peer; 63636285Sbrian int s; 63736285Sbrian 63836285Sbrian s = ID0socket(AF_INET, SOCK_DGRAM, 0); 63936285Sbrian if (s < 0) { 64036285Sbrian log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno)); 64136285Sbrian return; 64236285Sbrian } 64336285Sbrian 64436285Sbrian route_Clean(ipcp->fsm.bundle, ipcp->route); 64536285Sbrian 64636285Sbrian if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) 64736285Sbrian arp_ClearProxy(ipcp->fsm.bundle, ipcp->peer_ifip, s); 64836285Sbrian 64936285Sbrian if (ipcp->my_ifip.s_addr != INADDR_ANY || 65036285Sbrian ipcp->peer_ifip.s_addr != INADDR_ANY) { 65136285Sbrian memset(&ifra, '\0', sizeof ifra); 65236285Sbrian strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifp.Name, 65336285Sbrian sizeof ifra.ifra_name - 1); 65436285Sbrian ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 65536285Sbrian me = (struct sockaddr_in *)&ifra.ifra_addr; 65636285Sbrian peer = (struct sockaddr_in *)&ifra.ifra_broadaddr; 65736285Sbrian me->sin_family = peer->sin_family = AF_INET; 65836285Sbrian me->sin_len = peer->sin_len = sizeof(struct sockaddr_in); 65936285Sbrian me->sin_addr = ipcp->my_ifip; 66036285Sbrian peer->sin_addr = ipcp->peer_ifip; 66136285Sbrian if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) 66236285Sbrian log_Printf(LogERROR, "ipcp_CleanInterface: ioctl(SIOCDIFADDR): %s\n", 66336285Sbrian strerror(errno)); 66436285Sbrian ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY; 66536285Sbrian } 66636285Sbrian 66736285Sbrian close(s); 6686059Samurai} 6696059Samurai 6706059Samuraistatic void 67136285SbrianIpcpLayerDown(struct fsm *fp) 6726059Samurai{ 67336285Sbrian /* About to come down */ 67436285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 67536285Sbrian const char *s; 6766059Samurai 67736285Sbrian s = inet_ntoa(ipcp->peer_ifip); 67837210Sbrian log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s); 67930187Sbrian 68036285Sbrian /* 68136285Sbrian * XXX this stuff should really live in the FSM. Our config should 68236285Sbrian * associate executable sections in files with events. 68336285Sbrian */ 68437008Sbrian if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) { 68536285Sbrian if (bundle_GetLabel(fp->bundle)) { 68636285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 68737008Sbrian LINKDOWNFILE, NULL, NULL) < 0) 68837008Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 68936285Sbrian } else 69037008Sbrian system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL); 69136285Sbrian } 69230187Sbrian 69336928Sbrian if (!(ipcp->fsm.bundle->phys_type.all & PHYS_AUTO)) 69436285Sbrian ipcp_CleanInterface(ipcp); 69537160Sbrian 69637160Sbrian ipcp_Setup(ipcp); 69736285Sbrian} 69836285Sbrian 69936285Sbrianint 70036285Sbrianipcp_InterfaceUp(struct ipcp *ipcp) 70136285Sbrian{ 70236285Sbrian if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { 70337019Sbrian log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n"); 70436285Sbrian return 0; 70525630Sbrian } 70636285Sbrian 70731343Sbrian#ifndef NOALIAS 70837191Sbrian if (ipcp->fsm.bundle->AliasEnabled) 70937191Sbrian PacketAliasSetAddress(ipcp->my_ip); 71031343Sbrian#endif 71136285Sbrian 71236285Sbrian return 1; 7136059Samurai} 7146059Samurai 71536285Sbrianstatic int 71636285SbrianIpcpLayerUp(struct fsm *fp) 7176059Samurai{ 71836285Sbrian /* We're now up */ 71936285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 72036285Sbrian char tbuff[100]; 7216059Samurai 72237210Sbrian log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name); 72336285Sbrian snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip)); 72436285Sbrian log_Printf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip)); 72536285Sbrian 72636285Sbrian if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 72736285Sbrian sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); 72836285Sbrian 72936285Sbrian if (!ipcp_InterfaceUp(ipcp)) 73036285Sbrian return 0; 73136285Sbrian 73236285Sbrian /* 73336285Sbrian * XXX this stuff should really live in the FSM. Our config should 73436285Sbrian * associate executable sections in files with events. 73536285Sbrian */ 73637008Sbrian if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, 73737008Sbrian NULL, NULL) < 0) { 73836285Sbrian if (bundle_GetLabel(fp->bundle)) { 73936285Sbrian if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 74037008Sbrian LINKUPFILE, NULL, NULL) < 0) 74137008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 74236285Sbrian } else 74337008Sbrian system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL); 74436285Sbrian } 74536285Sbrian 74636314Sbrian log_DisplayPrompts(); 74736285Sbrian return 1; 7486059Samurai} 7496059Samurai 7506059Samuraistatic int 75136285SbrianAcceptableAddr(struct in_range *prange, struct in_addr ipaddr) 7526059Samurai{ 75336285Sbrian /* Is the given IP in the given range ? */ 75425661Sbrian return (prange->ipaddr.s_addr & prange->mask.s_addr) == 75528679Sbrian (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 7566059Samurai} 7576059Samurai 7586059Samuraistatic void 75936285SbrianIpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type, 76036285Sbrian struct fsm_decode *dec) 7616059Samurai{ 76236285Sbrian /* Deal with incoming PROTO_IPCP */ 76336285Sbrian struct ipcp *ipcp = fsm2ipcp(fp); 7646735Samurai int type, length; 76536285Sbrian u_int32_t compproto; 7666059Samurai struct compreq *pcomp; 76736285Sbrian struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; 76836285Sbrian char tbuff[100], tbuff2[100]; 76936285Sbrian int gotdns, gotdnsnak; 7706059Samurai 77136285Sbrian gotdns = 0; 77236285Sbrian gotdnsnak = 0; 77336285Sbrian dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; 7746059Samurai 7756059Samurai while (plen >= sizeof(struct fsmconfig)) { 7766059Samurai type = *cp; 7776059Samurai length = cp[1]; 77836285Sbrian 77936285Sbrian if (length == 0) { 78036285Sbrian log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); 78136285Sbrian break; 78236285Sbrian } 78336285Sbrian 78431171Sbrian if (type < NCFTYPES) 78531962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); 78631171Sbrian else if (type > 128 && type < 128 + NCFTYPES128) 78731962Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); 7886059Samurai else 78931962Sbrian snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); 7906059Samurai 7916059Samurai switch (type) { 7926059Samurai case TY_IPADDR: /* RFC1332 */ 79336285Sbrian ipaddr.s_addr = *(u_int32_t *)(cp + 2); 79436285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 7956059Samurai 79631034Sbrian switch (mode_type) { 7976059Samurai case MODE_REQ: 79836285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 79931850Sbrian if (ipaddr.s_addr == INADDR_ANY || 80036285Sbrian iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || 80136285Sbrian ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, 80236285Sbrian ipaddr, 1)) { 80336285Sbrian log_Printf(LogIPCP, "%s: Address invalid or already in use\n", 80431690Sbrian inet_ntoa(ipaddr)); 80536285Sbrian if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0) 80636285Sbrian /* 80736285Sbrian * If we've already got a valid address configured for the peer 80836465Sbrian * (in AUTO mode), try NAKing with that so that we don't 80936285Sbrian * have to upset things too much. 81036285Sbrian */ 81136285Sbrian ipcp->peer_ip = ipcp->peer_ifip; 81236285Sbrian else 81336285Sbrian /* Just pick an IP number from our list */ 81436285Sbrian ipcp->peer_ip = ChooseHisAddr 81536285Sbrian (fp->bundle, ipcp->cfg.my_range.ipaddr); 81636285Sbrian 81736285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 81836285Sbrian memcpy(dec->rejend, cp, length); 81936285Sbrian dec->rejend += length; 82031690Sbrian } else { 82136285Sbrian memcpy(dec->nakend, cp, 2); 82236285Sbrian memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); 82336285Sbrian dec->nakend += length; 82431690Sbrian } 82531690Sbrian break; 82631690Sbrian } 82736285Sbrian } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { 82828679Sbrian /* 82936285Sbrian * If destination address is not acceptable, NAK with what we 83028679Sbrian * want to use. 83128679Sbrian */ 83236285Sbrian memcpy(dec->nakend, cp, 2); 83336285Sbrian if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) == 83436285Sbrian (ipcp->cfg.peer_range.ipaddr.s_addr & 83536285Sbrian ipcp->cfg.peer_range.mask.s_addr)) 83636285Sbrian /* We prefer the already-configured address */ 83736285Sbrian memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2); 83836285Sbrian else 83936285Sbrian memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); 84036285Sbrian dec->nakend += length; 84128679Sbrian break; 8426059Samurai } 84336285Sbrian ipcp->peer_ip = ipaddr; 84436285Sbrian memcpy(dec->ackend, cp, length); 84536285Sbrian dec->ackend += length; 8466059Samurai break; 8476059Samurai case MODE_NAK: 84836285Sbrian if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { 84931690Sbrian /* Use address suggested by peer */ 85031962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 85136285Sbrian inet_ntoa(ipcp->my_ip)); 85236285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 85336285Sbrian ipcp->my_ip = ipaddr; 85431690Sbrian } else { 85536285Sbrian log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, 85636285Sbrian "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 85736285Sbrian fsm_Close(&ipcp->fsm); 8586059Samurai } 8596059Samurai break; 8606059Samurai case MODE_REJ: 86136285Sbrian ipcp->peer_reject |= (1 << type); 8626059Samurai break; 8636059Samurai } 8646059Samurai break; 8656059Samurai case TY_COMPPROTO: 86636285Sbrian compproto = htonl(*(u_int32_t *)(cp + 2)); 86736285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 8686059Samurai 86931034Sbrian switch (mode_type) { 8706059Samurai case MODE_REQ: 87136285Sbrian if (!IsAccepted(ipcp->cfg.vj.neg)) { 87236285Sbrian memcpy(dec->rejend, cp, length); 87336285Sbrian dec->rejend += length; 8746059Samurai } else { 87528679Sbrian pcomp = (struct compreq *) (cp + 2); 8766059Samurai switch (length) { 87728679Sbrian case 4: /* RFC1172 */ 8786059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 87936285Sbrian log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); 88036285Sbrian ipcp->heis1172 = 1; 88136285Sbrian ipcp->peer_compproto = compproto; 88236285Sbrian memcpy(dec->ackend, cp, length); 88336285Sbrian dec->ackend += length; 8846059Samurai } else { 88536285Sbrian memcpy(dec->nakend, cp, 2); 8866059Samurai pcomp->proto = htons(PROTO_VJCOMP); 88736285Sbrian memcpy(dec->nakend+2, &pcomp, 2); 88836285Sbrian dec->nakend += length; 8896059Samurai } 8906059Samurai break; 89128679Sbrian case 6: /* RFC1332 */ 8926059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP 89336285Sbrian && pcomp->slots <= MAX_VJ_STATES 89436285Sbrian && pcomp->slots >= MIN_VJ_STATES) { 89536285Sbrian ipcp->peer_compproto = compproto; 89636285Sbrian ipcp->heis1172 = 0; 89736285Sbrian memcpy(dec->ackend, cp, length); 89836285Sbrian dec->ackend += length; 8996059Samurai } else { 90036285Sbrian memcpy(dec->nakend, cp, 2); 9016059Samurai pcomp->proto = htons(PROTO_VJCOMP); 90236285Sbrian pcomp->slots = DEF_VJ_STATES; 9036059Samurai pcomp->compcid = 0; 90436285Sbrian memcpy(dec->nakend+2, &pcomp, sizeof pcomp); 90536285Sbrian dec->nakend += length; 9066059Samurai } 9076059Samurai break; 9086059Samurai default: 90936285Sbrian memcpy(dec->rejend, cp, length); 91036285Sbrian dec->rejend += length; 9116059Samurai break; 9126059Samurai } 9136059Samurai } 9146059Samurai break; 9156059Samurai case MODE_NAK: 91636285Sbrian log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 91736285Sbrian tbuff, ipcp->my_compproto, compproto); 91836285Sbrian ipcp->my_compproto = compproto; 9196059Samurai break; 9206059Samurai case MODE_REJ: 92136285Sbrian ipcp->peer_reject |= (1 << type); 9226059Samurai break; 9236059Samurai } 9246059Samurai break; 92528679Sbrian case TY_IPADDRS: /* RFC1172 */ 92636285Sbrian ipaddr.s_addr = *(u_int32_t *)(cp + 2); 92736285Sbrian dstipaddr.s_addr = *(u_int32_t *)(cp + 6); 92831962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 92936285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 9306059Samurai 93131034Sbrian switch (mode_type) { 9326059Samurai case MODE_REQ: 93336285Sbrian ipcp->peer_ip = ipaddr; 93436285Sbrian ipcp->my_ip = dstipaddr; 93536285Sbrian memcpy(dec->ackend, cp, length); 93636285Sbrian dec->ackend += length; 9376059Samurai break; 9386059Samurai case MODE_NAK: 93931962Sbrian snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff, 94036285Sbrian inet_ntoa(ipcp->my_ip)); 94136285Sbrian log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 94236285Sbrian ipcp->my_ip = ipaddr; 94336285Sbrian ipcp->peer_ip = dstipaddr; 9446059Samurai break; 9456059Samurai case MODE_REJ: 94636285Sbrian ipcp->peer_reject |= (1 << type); 9476059Samurai break; 9486059Samurai } 9496059Samurai break; 95018752Sjkh 95136285Sbrian case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ 95236285Sbrian case TY_SECONDARY_DNS: 95336285Sbrian ipaddr.s_addr = *(u_int32_t *)(cp + 2); 95436285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 95518752Sjkh 95631034Sbrian switch (mode_type) { 95718752Sjkh case MODE_REQ: 95836285Sbrian if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { 95936285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 96036285Sbrian memcpy(dec->rejend, cp, length); 96136285Sbrian dec->rejend += length; 96236285Sbrian break; 96336285Sbrian } 96436285Sbrian if (!gotdns) { 96536285Sbrian dns[0] = ipcp->cfg.ns.dns[0]; 96636285Sbrian dns[1] = ipcp->cfg.ns.dns[1]; 96736285Sbrian if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) 96836285Sbrian getdns(ipcp, dns); 96936285Sbrian gotdns = 1; 97036285Sbrian } 97136285Sbrian have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; 97228679Sbrian 97336285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 97418752Sjkh /* 97536285Sbrian * The client has got the DNS stuff wrong (first request) so 97628974Sbrian * we'll tell 'em how it is 97728679Sbrian */ 97836285Sbrian memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ 97936285Sbrian memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); 98036285Sbrian dec->nakend += length; 98136285Sbrian } else { 98236285Sbrian /* 98336285Sbrian * Otherwise they have it right (this time) so we send a ack packet 98436285Sbrian * back confirming it... end of story 98536285Sbrian */ 98636285Sbrian memcpy(dec->ackend, cp, length); 98736285Sbrian dec->ackend += length; 98836285Sbrian } 98918752Sjkh break; 99028679Sbrian case MODE_NAK: /* what does this mean?? */ 99136285Sbrian if (IsEnabled(ipcp->cfg.ns.dns_neg)) { 99236285Sbrian gotdnsnak = 1; 99336285Sbrian dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr = 99436285Sbrian *(u_int32_t *)(cp + 2); 99536285Sbrian } 99618752Sjkh break; 99736285Sbrian case MODE_REJ: /* Can't do much, stop asking */ 99836285Sbrian ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); 99918752Sjkh break; 100018752Sjkh } 100118752Sjkh break; 100218752Sjkh 100336285Sbrian case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ 100418752Sjkh case TY_SECONDARY_NBNS: 100536285Sbrian ipaddr.s_addr = *(u_int32_t *)(cp + 2); 100636285Sbrian log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 100736285Sbrian 100831034Sbrian switch (mode_type) { 100918752Sjkh case MODE_REQ: 101036285Sbrian have_ip.s_addr = 101136285Sbrian ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; 101236285Sbrian 101336285Sbrian if (have_ip.s_addr == INADDR_ANY) { 101436285Sbrian log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); 101536285Sbrian ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); 101636285Sbrian memcpy(dec->rejend, cp, length); 101736285Sbrian dec->rejend += length; 101818752Sjkh break; 101936285Sbrian } 102036285Sbrian 102136285Sbrian if (ipaddr.s_addr != have_ip.s_addr) { 102236285Sbrian memcpy(dec->nakend, cp, 2); 102336285Sbrian memcpy(dec->nakend+2, &have_ip.s_addr, length); 102436285Sbrian dec->nakend += length; 102536285Sbrian } else { 102636285Sbrian memcpy(dec->ackend, cp, length); 102736285Sbrian dec->ackend += length; 102836285Sbrian } 102918752Sjkh break; 103018752Sjkh case MODE_NAK: 103136285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 103218752Sjkh break; 103318752Sjkh case MODE_REJ: 103436285Sbrian log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 103518752Sjkh break; 103618752Sjkh } 103718752Sjkh break; 103818752Sjkh 10396059Samurai default: 104036285Sbrian if (mode_type != MODE_NOP) { 104136285Sbrian ipcp->my_reject |= (1 << type); 104236285Sbrian memcpy(dec->rejend, cp, length); 104336285Sbrian dec->rejend += length; 104436285Sbrian } 10456059Samurai break; 10466059Samurai } 10476059Samurai plen -= length; 10486059Samurai cp += length; 10496059Samurai } 105036285Sbrian 105136285Sbrian if (gotdnsnak) 105236285Sbrian if (!setdns(ipcp, dnsnak)) { 105336285Sbrian ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); 105436285Sbrian ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); 105536285Sbrian } 105636285Sbrian 105736285Sbrian if (mode_type != MODE_NOP) { 105836285Sbrian if (dec->rejend != dec->rej) { 105936285Sbrian /* rejects are preferred */ 106036285Sbrian dec->ackend = dec->ack; 106136285Sbrian dec->nakend = dec->nak; 106236285Sbrian } else if (dec->nakend != dec->nak) 106336285Sbrian /* then NAKs */ 106436285Sbrian dec->ackend = dec->ack; 106536285Sbrian } 10666059Samurai} 10676059Samurai 10686059Samuraivoid 106936285Sbrianipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp) 10706059Samurai{ 107136285Sbrian /* Got PROTO_IPCP from link */ 107236285Sbrian if (bundle_Phase(bundle) == PHASE_NETWORK) 107336285Sbrian fsm_Input(&ipcp->fsm, bp); 107436285Sbrian else { 107536285Sbrian if (bundle_Phase(bundle) < PHASE_NETWORK) 107636285Sbrian log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", 107736285Sbrian ipcp->fsm.link->name, bundle_PhaseName(bundle)); 107836285Sbrian mbuf_Free(bp); 107936285Sbrian } 10806059Samurai} 108132267Sbrian 108232267Sbrianint 108336285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 108432267Sbrian{ 108536285Sbrian struct ipcp *ipcp = &bundle->ncp.ipcp; 108636285Sbrian 108736285Sbrian /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 108836285Sbrian memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 108936285Sbrian iplist_reset(&ipcp->cfg.peer_list); 109032267Sbrian if (strpbrk(hisaddr, ",-")) { 109136285Sbrian iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); 109236285Sbrian if (iplist_isvalid(&ipcp->cfg.peer_list)) { 109336285Sbrian iplist_setrandpos(&ipcp->cfg.peer_list); 109436285Sbrian ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); 109536285Sbrian if (ipcp->peer_ip.s_addr == INADDR_ANY) { 109636285Sbrian log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); 109732267Sbrian return(0); 109832267Sbrian } 109936285Sbrian ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; 110036285Sbrian ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 110136285Sbrian ipcp->cfg.peer_range.width = 32; 110232267Sbrian } else { 110336285Sbrian log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); 110432267Sbrian return 0; 110532267Sbrian } 110636285Sbrian } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr, 110736285Sbrian &ipcp->cfg.peer_range.mask, 110836285Sbrian &ipcp->cfg.peer_range.width) != 0) { 110936285Sbrian ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; 111032267Sbrian 111136285Sbrian if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, 111236285Sbrian ipcp->cfg.peer_range.ipaddr, 0) < 0) { 111336285Sbrian ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY; 111436285Sbrian ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY; 111532267Sbrian return 0; 111632267Sbrian } 111732267Sbrian } else 111832267Sbrian return 0; 111932267Sbrian 112032267Sbrian return 1; 112132267Sbrian} 1122