11ae349f5Scvs2svn /* 21ae349f5Scvs2svn * PPP IP Control Protocol (IPCP) Module 31ae349f5Scvs2svn * 41ae349f5Scvs2svn * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 51ae349f5Scvs2svn * 61ae349f5Scvs2svn * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 71ae349f5Scvs2svn * 81ae349f5Scvs2svn * Redistribution and use in source and binary forms are permitted 91ae349f5Scvs2svn * provided that the above copyright notice and this paragraph are 101ae349f5Scvs2svn * duplicated in all such forms and that any documentation, 111ae349f5Scvs2svn * advertising materials, and other materials related to such 121ae349f5Scvs2svn * distribution and use acknowledge that the software was developed 131ae349f5Scvs2svn * by the Internet Initiative Japan, Inc. The name of the 141ae349f5Scvs2svn * IIJ may not be used to endorse or promote products derived 151ae349f5Scvs2svn * from this software without specific prior written permission. 161ae349f5Scvs2svn * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 171ae349f5Scvs2svn * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 181ae349f5Scvs2svn * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 191ae349f5Scvs2svn * 20503a7782SBrian Somers * $Id: ipcp.c,v 1.50.2.14 1998/02/19 19:56:59 brian Exp $ 211ae349f5Scvs2svn * 221ae349f5Scvs2svn * TODO: 231ae349f5Scvs2svn * o More RFC1772 backwoard compatibility 241ae349f5Scvs2svn */ 251ae349f5Scvs2svn #include <sys/param.h> 261ae349f5Scvs2svn #include <netinet/in_systm.h> 271ae349f5Scvs2svn #include <netinet/in.h> 281ae349f5Scvs2svn #include <netinet/ip.h> 291ae349f5Scvs2svn #include <arpa/inet.h> 301ae349f5Scvs2svn #include <sys/socket.h> 311ae349f5Scvs2svn #include <netdb.h> 32455aabc3SBrian Somers #include <sys/time.h> 33455aabc3SBrian Somers #include <net/if.h> 34455aabc3SBrian Somers #include <sys/sockio.h> 351ae349f5Scvs2svn 361ae349f5Scvs2svn #include <stdio.h> 371ae349f5Scvs2svn #include <stdlib.h> 381ae349f5Scvs2svn #include <string.h> 39455aabc3SBrian Somers #include <sys/errno.h> 406140ba11SBrian Somers #include <termios.h> 411ae349f5Scvs2svn #include <unistd.h> 421ae349f5Scvs2svn 431ae349f5Scvs2svn #include "command.h" 441ae349f5Scvs2svn #include "mbuf.h" 451ae349f5Scvs2svn #include "log.h" 461ae349f5Scvs2svn #include "defs.h" 471ae349f5Scvs2svn #include "timer.h" 481ae349f5Scvs2svn #include "fsm.h" 491ae349f5Scvs2svn #include "lcpproto.h" 501ae349f5Scvs2svn #include "lcp.h" 511ae349f5Scvs2svn #include "iplist.h" 5229e275ceSBrian Somers #include "throughput.h" 531ae349f5Scvs2svn #include "ipcp.h" 541ae349f5Scvs2svn #include "slcompress.h" 557a6f8720SBrian Somers #include "bundle.h" 561ae349f5Scvs2svn #include "loadalias.h" 571ae349f5Scvs2svn #include "vars.h" 581ae349f5Scvs2svn #include "vjcomp.h" 591ae349f5Scvs2svn #include "ip.h" 601ae349f5Scvs2svn #include "route.h" 611ae349f5Scvs2svn #include "filter.h" 628c07a7b2SBrian Somers #include "hdlc.h" 636140ba11SBrian Somers #include "async.h" 648c07a7b2SBrian Somers #include "link.h" 6542d4d396SBrian Somers #include "descriptor.h" 6663b73463SBrian Somers #include "physical.h" 67455aabc3SBrian Somers #include "id.h" 68455aabc3SBrian Somers #include "arp.h" 69455aabc3SBrian Somers #include "systems.h" 7085b542cfSBrian Somers #include "prompt.h" 711ae349f5Scvs2svn 72503a7782SBrian Somers #undef REJECTED 73503a7782SBrian Somers #define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) 74503a7782SBrian Somers 7529e275ceSBrian Somers struct compreq { 7629e275ceSBrian Somers u_short proto; 7729e275ceSBrian Somers u_char slots; 7829e275ceSBrian Somers u_char compcid; 7929e275ceSBrian Somers }; 801ae349f5Scvs2svn 811ae349f5Scvs2svn static void IpcpLayerUp(struct fsm *); 821ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *); 837308ec68SBrian Somers static void IpcpLayerStart(struct fsm *); 847308ec68SBrian Somers static void IpcpLayerFinish(struct fsm *); 851ae349f5Scvs2svn static void IpcpInitRestartCounter(struct fsm *); 867308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *); 877308ec68SBrian Somers static void IpcpSendTerminateReq(struct fsm *); 887308ec68SBrian Somers static void IpcpSendTerminateAck(struct fsm *); 8983d1af55SBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int); 9083d1af55SBrian Somers 9183d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = { 9283d1af55SBrian Somers IpcpLayerUp, 9383d1af55SBrian Somers IpcpLayerDown, 9483d1af55SBrian Somers IpcpLayerStart, 9583d1af55SBrian Somers IpcpLayerFinish, 9683d1af55SBrian Somers IpcpInitRestartCounter, 9783d1af55SBrian Somers IpcpSendConfigReq, 9883d1af55SBrian Somers IpcpSendTerminateReq, 9983d1af55SBrian Somers IpcpSendTerminateAck, 10083d1af55SBrian Somers IpcpDecodeConfig, 101503a7782SBrian Somers NullRecvResetReq, 102503a7782SBrian Somers NullRecvResetAck 10383d1af55SBrian Somers }; 1041ae349f5Scvs2svn 105503a7782SBrian Somers struct ipcp IpcpInfo; 1061ae349f5Scvs2svn 1071ae349f5Scvs2svn static const char *cftypes[] = { 1081ae349f5Scvs2svn /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 1091ae349f5Scvs2svn "???", 1101ae349f5Scvs2svn "IPADDRS", /* 1: IP-Addresses */ /* deprecated */ 1111ae349f5Scvs2svn "COMPPROTO", /* 2: IP-Compression-Protocol */ 1121ae349f5Scvs2svn "IPADDR", /* 3: IP-Address */ 1131ae349f5Scvs2svn }; 1141ae349f5Scvs2svn 1151ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 1161ae349f5Scvs2svn 1171ae349f5Scvs2svn static const char *cftypes128[] = { 1181ae349f5Scvs2svn /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 1191ae349f5Scvs2svn "???", 1201ae349f5Scvs2svn "PRIDNS", /* 129: Primary DNS Server Address */ 1211ae349f5Scvs2svn "PRINBNS", /* 130: Primary NBNS Server Address */ 1221ae349f5Scvs2svn "SECDNS", /* 131: Secondary DNS Server Address */ 1231ae349f5Scvs2svn "SECNBNS", /* 132: Secondary NBNS Server Address */ 1241ae349f5Scvs2svn }; 1251ae349f5Scvs2svn 1261ae349f5Scvs2svn #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) 1271ae349f5Scvs2svn 1281ae349f5Scvs2svn void 1291ae349f5Scvs2svn IpcpAddInOctets(int n) 1301ae349f5Scvs2svn { 13129e275ceSBrian Somers throughput_addin(&IpcpInfo.throughput, n); 1321ae349f5Scvs2svn } 1331ae349f5Scvs2svn 1341ae349f5Scvs2svn void 1351ae349f5Scvs2svn IpcpAddOutOctets(int n) 1361ae349f5Scvs2svn { 13729e275ceSBrian Somers throughput_addout(&IpcpInfo.throughput, n); 1381ae349f5Scvs2svn } 1391ae349f5Scvs2svn 1401ae349f5Scvs2svn int 1411ae349f5Scvs2svn ReportIpcpStatus(struct cmdargs const *arg) 1421ae349f5Scvs2svn { 14385b542cfSBrian Somers prompt_Printf(&prompt, "%s [%s]\n", IpcpInfo.fsm.name, 1447308ec68SBrian Somers StateNames[IpcpInfo.fsm.state]); 1457308ec68SBrian Somers if (IpcpInfo.fsm.state == ST_OPENED) { 14685b542cfSBrian Somers prompt_Printf(&prompt, " His side: %s, %s\n", 147503a7782SBrian Somers inet_ntoa(IpcpInfo.peer_ip), vj2asc(IpcpInfo.peer_compproto)); 14885b542cfSBrian Somers prompt_Printf(&prompt, " My side: %s, %s\n", 149503a7782SBrian Somers inet_ntoa(IpcpInfo.my_ip), vj2asc(IpcpInfo.my_compproto)); 1501ae349f5Scvs2svn } 1511ae349f5Scvs2svn 15285b542cfSBrian Somers prompt_Printf(&prompt, "\nDefaults:\n"); 15385b542cfSBrian Somers prompt_Printf(&prompt, " My Address: %s/%d\n", 154503a7782SBrian Somers inet_ntoa(IpcpInfo.cfg.my_range.ipaddr), IpcpInfo.cfg.my_range.width); 155503a7782SBrian Somers if (iplist_isvalid(&IpcpInfo.cfg.peer_list)) 15685b542cfSBrian Somers prompt_Printf(&prompt, " His Address: %s\n", 157503a7782SBrian Somers IpcpInfo.cfg.peer_list.src); 1581ae349f5Scvs2svn else 15985b542cfSBrian Somers prompt_Printf(&prompt, " His Address: %s/%d\n", 160503a7782SBrian Somers inet_ntoa(IpcpInfo.cfg.peer_range.ipaddr), 161503a7782SBrian Somers IpcpInfo.cfg.peer_range.width); 162503a7782SBrian Somers if (IpcpInfo.cfg.HaveTriggerAddress) 16385b542cfSBrian Somers prompt_Printf(&prompt, " Negotiation(trigger): %s\n", 164503a7782SBrian Somers inet_ntoa(IpcpInfo.cfg.TriggerAddress)); 1651ae349f5Scvs2svn else 16685b542cfSBrian Somers prompt_Printf(&prompt, " Negotiation(trigger): MYADDR\n"); 167503a7782SBrian Somers prompt_Printf(&prompt, " Initial VJ slots: %d\n", 168503a7782SBrian Somers IpcpInfo.cfg.VJInitSlots); 16985b542cfSBrian Somers prompt_Printf(&prompt, " Initial VJ compression: %s\n", 170503a7782SBrian Somers IpcpInfo.cfg.VJInitComp ? "on" : "off"); 1711ae349f5Scvs2svn 17285b542cfSBrian Somers prompt_Printf(&prompt, "\n"); 17385b542cfSBrian Somers throughput_disp(&IpcpInfo.throughput); 1741ae349f5Scvs2svn 1751ae349f5Scvs2svn return 0; 1761ae349f5Scvs2svn } 1771ae349f5Scvs2svn 1781ae349f5Scvs2svn int 1791ae349f5Scvs2svn SetInitVJ(struct cmdargs const *args) 1801ae349f5Scvs2svn { 1811ae349f5Scvs2svn if (args->argc != 2) 1821ae349f5Scvs2svn return -1; 1831ae349f5Scvs2svn if (!strcasecmp(args->argv[0], "slots")) { 1841ae349f5Scvs2svn int slots; 1851ae349f5Scvs2svn 1861ae349f5Scvs2svn slots = atoi(args->argv[1]); 1871ae349f5Scvs2svn if (slots < 4 || slots > 16) 1881ae349f5Scvs2svn return 1; 189503a7782SBrian Somers IpcpInfo.cfg.VJInitSlots = slots; 1901ae349f5Scvs2svn return 0; 1911ae349f5Scvs2svn } else if (!strcasecmp(args->argv[0], "slotcomp")) { 1921ae349f5Scvs2svn if (!strcasecmp(args->argv[1], "on")) 193503a7782SBrian Somers IpcpInfo.cfg.VJInitComp = 1; 1941ae349f5Scvs2svn else if (!strcasecmp(args->argv[1], "off")) 195503a7782SBrian Somers IpcpInfo.cfg.VJInitComp = 0; 1961ae349f5Scvs2svn else 1971ae349f5Scvs2svn return 2; 1981ae349f5Scvs2svn return 0; 1991ae349f5Scvs2svn } 2001ae349f5Scvs2svn return -1; 2011ae349f5Scvs2svn } 2021ae349f5Scvs2svn 2031ae349f5Scvs2svn void 204503a7782SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l) 2051ae349f5Scvs2svn { 206503a7782SBrian Somers struct hostent *hp; 207503a7782SBrian Somers char name[MAXHOSTNAMELEN]; 20829e275ceSBrian Somers 209503a7782SBrian Somers fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, IPCP_MAXCODE, 10, LogIPCP, 210503a7782SBrian Somers bundle, l, &ipcp_Callbacks); 211503a7782SBrian Somers 212503a7782SBrian Somers ipcp->cfg.VJInitSlots = DEF_VJ_STATES; 213503a7782SBrian Somers ipcp->cfg.VJInitComp = 1; 214503a7782SBrian Somers memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); 215503a7782SBrian Somers if (gethostname(name, sizeof name) == 0) { 216503a7782SBrian Somers hp = gethostbyname(name); 217503a7782SBrian Somers if (hp && hp->h_addrtype == AF_INET) { 218503a7782SBrian Somers memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); 219503a7782SBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 220503a7782SBrian Somers ipcp->cfg.peer_range.width = 32; 2211ae349f5Scvs2svn } 222503a7782SBrian Somers } 223503a7782SBrian Somers memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); 224503a7782SBrian Somers iplist_setsrc(&ipcp->cfg.peer_list, ""); 225503a7782SBrian Somers ipcp->cfg.HaveTriggerAddress = 0; 226503a7782SBrian Somers 227503a7782SBrian Somers ipcp->cfg.ns_entries[0].s_addr = INADDR_ANY; 228503a7782SBrian Somers ipcp->cfg.ns_entries[1].s_addr = INADDR_ANY; 229503a7782SBrian Somers ipcp->cfg.nbns_entries[0].s_addr = INADDR_ANY; 230503a7782SBrian Somers ipcp->cfg.nbns_entries[1].s_addr = INADDR_ANY; 231503a7782SBrian Somers 232503a7782SBrian Somers ipcp->my_ifip.s_addr = INADDR_ANY; 233503a7782SBrian Somers ipcp->peer_ifip.s_addr = INADDR_ANY; 234503a7782SBrian Somers 235503a7782SBrian Somers ipcp_Setup(ipcp); 236503a7782SBrian Somers } 237503a7782SBrian Somers 238503a7782SBrian Somers void 239503a7782SBrian Somers ipcp_Setup(struct ipcp *ipcp) 240503a7782SBrian Somers { 241503a7782SBrian Somers int pos; 242503a7782SBrian Somers 243503a7782SBrian Somers ipcp->fsm.open_mode = 0; 244503a7782SBrian Somers 245503a7782SBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 246503a7782SBrian Somers if (ipcp->my_ifip.s_addr != INADDR_ANY && 247503a7782SBrian Somers (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1) 248503a7782SBrian Somers ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos); 249503a7782SBrian Somers else 250503a7782SBrian Somers ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); 251503a7782SBrian Somers ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 252503a7782SBrian Somers ipcp->cfg.peer_range.width = 32; 253503a7782SBrian Somers } 254503a7782SBrian Somers 255503a7782SBrian Somers ipcp->heis1172 = 0; 256503a7782SBrian Somers 257503a7782SBrian Somers ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; 258503a7782SBrian Somers ipcp->peer_compproto = 0; 2591ae349f5Scvs2svn 2601ae349f5Scvs2svn /* 2611ae349f5Scvs2svn * Some implementations of PPP require that we send a 2621ae349f5Scvs2svn * *special* value as our address, even though the rfc specifies 2631ae349f5Scvs2svn * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). 2641ae349f5Scvs2svn */ 265503a7782SBrian Somers if (ipcp->cfg.HaveTriggerAddress) { 266503a7782SBrian Somers ipcp->my_ip = ipcp->cfg.TriggerAddress; 26729e275ceSBrian Somers LogPrintf(LogIPCP, "Using trigger address %s\n", 268503a7782SBrian Somers inet_ntoa(ipcp->cfg.TriggerAddress)); 269503a7782SBrian Somers } else 270503a7782SBrian Somers ipcp->my_ip = ipcp->cfg.my_range.ipaddr; 27129e275ceSBrian Somers 2721ae349f5Scvs2svn if (Enabled(ConfVjcomp)) 273503a7782SBrian Somers ipcp->my_compproto = (PROTO_VJCOMP << 16) + 274503a7782SBrian Somers ((ipcp->cfg.VJInitSlots - 1) << 8) + 275503a7782SBrian Somers ipcp->cfg.VJInitComp; 2761ae349f5Scvs2svn else 277503a7782SBrian Somers ipcp->my_compproto = 0; 278503a7782SBrian Somers VjInit(ipcp->cfg.VJInitSlots - 1); 27929e275ceSBrian Somers 280503a7782SBrian Somers ipcp->peer_reject = 0; 281503a7782SBrian Somers ipcp->my_reject = 0; 282503a7782SBrian Somers 283503a7782SBrian Somers throughput_init(&ipcp->throughput); 2841ae349f5Scvs2svn } 2851ae349f5Scvs2svn 286455aabc3SBrian Somers static int 287aad81d1eSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct ipcp *ipcp, 288455aabc3SBrian Somers struct in_addr myaddr, struct in_addr hisaddr, 289455aabc3SBrian Somers struct in_addr netmask, int silent) 290455aabc3SBrian Somers { 291455aabc3SBrian Somers struct sockaddr_in *sock_in; 292455aabc3SBrian Somers int s; 293455aabc3SBrian Somers u_long mask, addr; 294455aabc3SBrian Somers struct ifaliasreq ifra; 295455aabc3SBrian Somers 296455aabc3SBrian Somers /* If given addresses are alreay set, then ignore this request */ 297503a7782SBrian Somers if (ipcp->my_ifip.s_addr == myaddr.s_addr && 298503a7782SBrian Somers ipcp->peer_ifip.s_addr == hisaddr.s_addr) 299455aabc3SBrian Somers return 0; 300455aabc3SBrian Somers 30168a0f0ccSBrian Somers IpcpCleanInterface(&ipcp->fsm); 30268a0f0ccSBrian Somers 303455aabc3SBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 304455aabc3SBrian Somers if (s < 0) { 305455aabc3SBrian Somers LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno)); 306455aabc3SBrian Somers return (-1); 307455aabc3SBrian Somers } 308455aabc3SBrian Somers 309455aabc3SBrian Somers memset(&ifra, '\0', sizeof ifra); 310455aabc3SBrian Somers strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1); 311455aabc3SBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 312455aabc3SBrian Somers 313455aabc3SBrian Somers /* Set interface address */ 314455aabc3SBrian Somers sock_in = (struct sockaddr_in *)&ifra.ifra_addr; 315455aabc3SBrian Somers sock_in->sin_family = AF_INET; 316455aabc3SBrian Somers sock_in->sin_addr = myaddr; 317455aabc3SBrian Somers sock_in->sin_len = sizeof *sock_in; 318455aabc3SBrian Somers 319455aabc3SBrian Somers /* Set destination address */ 320455aabc3SBrian Somers sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr; 321455aabc3SBrian Somers sock_in->sin_family = AF_INET; 322455aabc3SBrian Somers sock_in->sin_addr = hisaddr; 323455aabc3SBrian Somers sock_in->sin_len = sizeof *sock_in; 324455aabc3SBrian Somers 325455aabc3SBrian Somers addr = ntohl(myaddr.s_addr); 326455aabc3SBrian Somers if (IN_CLASSA(addr)) 327455aabc3SBrian Somers mask = IN_CLASSA_NET; 328455aabc3SBrian Somers else if (IN_CLASSB(addr)) 329455aabc3SBrian Somers mask = IN_CLASSB_NET; 330455aabc3SBrian Somers else 331455aabc3SBrian Somers mask = IN_CLASSC_NET; 332455aabc3SBrian Somers 333455aabc3SBrian Somers /* if subnet mask is given, use it instead of class mask */ 334455aabc3SBrian Somers if (netmask.s_addr != INADDR_ANY && (ntohl(netmask.s_addr) & mask) == mask) 335455aabc3SBrian Somers mask = ntohl(netmask.s_addr); 336455aabc3SBrian Somers 337455aabc3SBrian Somers sock_in = (struct sockaddr_in *)&ifra.ifra_mask; 338455aabc3SBrian Somers sock_in->sin_family = AF_INET; 339455aabc3SBrian Somers sock_in->sin_addr.s_addr = htonl(mask); 340455aabc3SBrian Somers sock_in->sin_len = sizeof *sock_in; 341455aabc3SBrian Somers 342455aabc3SBrian Somers if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { 343455aabc3SBrian Somers if (!silent) 344455aabc3SBrian Somers LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n", 345455aabc3SBrian Somers strerror(errno)); 346455aabc3SBrian Somers close(s); 347455aabc3SBrian Somers return (-1); 348455aabc3SBrian Somers } 349455aabc3SBrian Somers 350503a7782SBrian Somers ipcp->peer_ifip.s_addr = hisaddr.s_addr; 351503a7782SBrian Somers ipcp->my_ifip.s_addr = myaddr.s_addr; 352455aabc3SBrian Somers 353455aabc3SBrian Somers if (Enabled(ConfProxy)) 354503a7782SBrian Somers sifproxyarp(bundle, ipcp->peer_ifip, s); 355455aabc3SBrian Somers 356455aabc3SBrian Somers close(s); 357455aabc3SBrian Somers return (0); 358455aabc3SBrian Somers } 359455aabc3SBrian Somers 360455aabc3SBrian Somers static struct in_addr 361aad81d1eSBrian Somers ChooseHisAddr(struct bundle *bundle, struct ipcp *ipcp, 362455aabc3SBrian Somers const struct in_addr gw) 363455aabc3SBrian Somers { 364455aabc3SBrian Somers struct in_addr try; 365455aabc3SBrian Somers int f; 366455aabc3SBrian Somers 367503a7782SBrian Somers for (f = 0; f < IpcpInfo.cfg.peer_list.nItems; f++) { 368503a7782SBrian Somers try = iplist_next(&IpcpInfo.cfg.peer_list); 369455aabc3SBrian Somers LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n", 370455aabc3SBrian Somers f, inet_ntoa(try)); 371455aabc3SBrian Somers if (ipcp_SetIPaddress(bundle, ipcp, gw, try, ifnetmask, 1) == 0) { 372455aabc3SBrian Somers LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n", 373455aabc3SBrian Somers inet_ntoa(try)); 374455aabc3SBrian Somers break; 375455aabc3SBrian Somers } 376455aabc3SBrian Somers } 377455aabc3SBrian Somers 378503a7782SBrian Somers if (f == IpcpInfo.cfg.peer_list.nItems) { 379455aabc3SBrian Somers LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); 380455aabc3SBrian Somers try.s_addr = INADDR_ANY; 381455aabc3SBrian Somers } 382455aabc3SBrian Somers 383455aabc3SBrian Somers return try; 384455aabc3SBrian Somers } 385455aabc3SBrian Somers 3861ae349f5Scvs2svn static void 3871ae349f5Scvs2svn IpcpInitRestartCounter(struct fsm * fp) 3881ae349f5Scvs2svn { 3897308ec68SBrian Somers /* Set fsm timer load */ 3901ae349f5Scvs2svn fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 3911ae349f5Scvs2svn fp->restart = 5; 3921ae349f5Scvs2svn } 3931ae349f5Scvs2svn 3941ae349f5Scvs2svn static void 3951ae349f5Scvs2svn IpcpSendConfigReq(struct fsm *fp) 3961ae349f5Scvs2svn { 3977308ec68SBrian Somers /* Send config REQ please */ 3988c07a7b2SBrian Somers struct physical *p = link2physical(fp->link); 399aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 4001ae349f5Scvs2svn u_char *cp; 4011ae349f5Scvs2svn struct lcp_opt o; 4021ae349f5Scvs2svn 4031ae349f5Scvs2svn cp = ReqBuff; 4041ae349f5Scvs2svn LogPrintf(LogIPCP, "IpcpSendConfigReq\n"); 40583d1af55SBrian Somers if ((p && !Physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { 4061ae349f5Scvs2svn o.id = TY_IPADDR; 4071ae349f5Scvs2svn o.len = 6; 408503a7782SBrian Somers *(u_long *)o.data = ipcp->my_ip.s_addr; 4091ae349f5Scvs2svn cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], 410503a7782SBrian Somers inet_ntoa(ipcp->my_ip)); 4111ae349f5Scvs2svn } 4121ae349f5Scvs2svn 413503a7782SBrian Somers if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { 4141ae349f5Scvs2svn const char *args; 4151ae349f5Scvs2svn o.id = TY_COMPPROTO; 41683d1af55SBrian Somers if (ipcp->heis1172) { 4171ae349f5Scvs2svn o.len = 4; 4181ae349f5Scvs2svn *(u_short *)o.data = htons(PROTO_VJCOMP); 4191ae349f5Scvs2svn args = ""; 4201ae349f5Scvs2svn } else { 4211ae349f5Scvs2svn o.len = 6; 422503a7782SBrian Somers *(u_long *)o.data = htonl(ipcp->my_compproto); 423503a7782SBrian Somers args = vj2asc(ipcp->my_compproto); 4241ae349f5Scvs2svn } 4251ae349f5Scvs2svn cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], args); 4261ae349f5Scvs2svn } 4271ae349f5Scvs2svn FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 4281ae349f5Scvs2svn } 4291ae349f5Scvs2svn 4301ae349f5Scvs2svn static void 4311ae349f5Scvs2svn IpcpSendTerminateReq(struct fsm * fp) 4321ae349f5Scvs2svn { 4337308ec68SBrian Somers /* Term REQ just sent by FSM */ 4341ae349f5Scvs2svn } 4351ae349f5Scvs2svn 4361ae349f5Scvs2svn static void 4371ae349f5Scvs2svn IpcpSendTerminateAck(struct fsm * fp) 4381ae349f5Scvs2svn { 4397308ec68SBrian Somers /* Send Term ACK please */ 4401ae349f5Scvs2svn LogPrintf(LogIPCP, "IpcpSendTerminateAck\n"); 4411ae349f5Scvs2svn FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 4421ae349f5Scvs2svn } 4431ae349f5Scvs2svn 4441ae349f5Scvs2svn static void 4451ae349f5Scvs2svn IpcpLayerStart(struct fsm * fp) 4461ae349f5Scvs2svn { 4477308ec68SBrian Somers /* We're about to start up ! */ 4481ae349f5Scvs2svn LogPrintf(LogIPCP, "IpcpLayerStart.\n"); 449455aabc3SBrian Somers 450455aabc3SBrian Somers /* This is where we should be setting up the interface in AUTO mode */ 4511ae349f5Scvs2svn } 4521ae349f5Scvs2svn 4531ae349f5Scvs2svn static void 4541ae349f5Scvs2svn IpcpLayerFinish(struct fsm *fp) 4551ae349f5Scvs2svn { 4567308ec68SBrian Somers /* We're now down */ 4571ae349f5Scvs2svn LogPrintf(LogIPCP, "IpcpLayerFinish.\n"); 4581ae349f5Scvs2svn } 4591ae349f5Scvs2svn 46068a0f0ccSBrian Somers void 46168a0f0ccSBrian Somers IpcpCleanInterface(struct fsm *fp) 46268a0f0ccSBrian Somers { 46368a0f0ccSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 46468a0f0ccSBrian Somers struct ifaliasreq ifra; 46568a0f0ccSBrian Somers struct sockaddr_in *me, *peer; 46668a0f0ccSBrian Somers int s; 46768a0f0ccSBrian Somers 46868a0f0ccSBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 46968a0f0ccSBrian Somers if (s < 0) { 47068a0f0ccSBrian Somers LogPrintf(LogERROR, "IpcpCleanInterface: socket: %s\n", strerror(errno)); 47168a0f0ccSBrian Somers return; 47268a0f0ccSBrian Somers } 47368a0f0ccSBrian Somers 47468a0f0ccSBrian Somers if (Enabled(ConfProxy)) 475503a7782SBrian Somers cifproxyarp(fp->bundle, ipcp->peer_ifip, s); 47668a0f0ccSBrian Somers 477503a7782SBrian Somers if (ipcp->my_ifip.s_addr != INADDR_ANY || 478503a7782SBrian Somers ipcp->peer_ifip.s_addr != INADDR_ANY) { 47968a0f0ccSBrian Somers memset(&ifra, '\0', sizeof ifra); 48068a0f0ccSBrian Somers strncpy(ifra.ifra_name, fp->bundle->ifname, sizeof ifra.ifra_name - 1); 48168a0f0ccSBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 48268a0f0ccSBrian Somers me = (struct sockaddr_in *)&ifra.ifra_addr; 48368a0f0ccSBrian Somers peer = (struct sockaddr_in *)&ifra.ifra_broadaddr; 48468a0f0ccSBrian Somers me->sin_family = peer->sin_family = AF_INET; 48568a0f0ccSBrian Somers me->sin_len = peer->sin_len = sizeof(struct sockaddr_in); 486503a7782SBrian Somers me->sin_addr = ipcp->my_ifip; 487503a7782SBrian Somers peer->sin_addr = ipcp->peer_ifip; 48868a0f0ccSBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 48968a0f0ccSBrian Somers LogPrintf(LogERROR, "IpcpCleanInterface: ioctl(SIOCDIFADDR): %s\n", 49068a0f0ccSBrian Somers strerror(errno)); 49168a0f0ccSBrian Somers close(s); 49268a0f0ccSBrian Somers } 493503a7782SBrian Somers ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY; 49468a0f0ccSBrian Somers } 49568a0f0ccSBrian Somers 49668a0f0ccSBrian Somers close(s); 49768a0f0ccSBrian Somers } 49868a0f0ccSBrian Somers 4991ae349f5Scvs2svn static void 5001ae349f5Scvs2svn IpcpLayerDown(struct fsm *fp) 5011ae349f5Scvs2svn { 5027308ec68SBrian Somers /* About to come down */ 503aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 504455aabc3SBrian Somers const char *s; 505455aabc3SBrian Somers 506503a7782SBrian Somers s = inet_ntoa(ipcp->peer_ifip); 507455aabc3SBrian Somers LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerDown: %s\n", s); 508455aabc3SBrian Somers 50983d1af55SBrian Somers throughput_stop(&ipcp->throughput); 51083d1af55SBrian Somers throughput_log(&ipcp->throughput, LogIPCP, NULL); 511455aabc3SBrian Somers 512455aabc3SBrian Somers /* 513455aabc3SBrian Somers * XXX this stuff should really live in the FSM. Our config should 514455aabc3SBrian Somers * associate executable sections in files with events. 515455aabc3SBrian Somers */ 516455aabc3SBrian Somers if (SelectSystem(fp->bundle, s, LINKDOWNFILE) < 0) 517455aabc3SBrian Somers if (GetLabel()) { 518455aabc3SBrian Somers if (SelectSystem(fp->bundle, GetLabel(), LINKDOWNFILE) < 0) 519455aabc3SBrian Somers SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE); 520455aabc3SBrian Somers } else 521455aabc3SBrian Somers SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE); 522455aabc3SBrian Somers 52368a0f0ccSBrian Somers if (!(mode & MODE_AUTO)) 52468a0f0ccSBrian Somers IpcpCleanInterface(fp); 5251ae349f5Scvs2svn } 5261ae349f5Scvs2svn 5271ae349f5Scvs2svn static void 5281ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp) 5291ae349f5Scvs2svn { 5307308ec68SBrian Somers /* We're now up */ 531aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 5321ae349f5Scvs2svn char tbuff[100]; 5331ae349f5Scvs2svn 5341ae349f5Scvs2svn LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state); 535503a7782SBrian Somers snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip)); 536455aabc3SBrian Somers LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n", 537503a7782SBrian Somers tbuff, inet_ntoa(ipcp->peer_ip)); 5381ae349f5Scvs2svn 539503a7782SBrian Somers if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) 540503a7782SBrian Somers VjInit((ipcp->peer_compproto >> 8) & 255); 5411ae349f5Scvs2svn 542503a7782SBrian Somers if (ipcp_SetIPaddress(fp->bundle, ipcp, ipcp->my_ip, 543503a7782SBrian Somers ipcp->peer_ip, ifnetmask, 0) < 0) { 5441ae349f5Scvs2svn LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n"); 5451ae349f5Scvs2svn return; 5461ae349f5Scvs2svn } 547455aabc3SBrian Somers 5481ae349f5Scvs2svn #ifndef NOALIAS 5491ae349f5Scvs2svn if (mode & MODE_ALIAS) 550503a7782SBrian Somers VarPacketAliasSetAddress(ipcp->my_ip); 5511ae349f5Scvs2svn #endif 552455aabc3SBrian Somers 553455aabc3SBrian Somers LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerUp: %s\n", 554503a7782SBrian Somers inet_ntoa(ipcp->peer_ifip)); 555455aabc3SBrian Somers 556455aabc3SBrian Somers /* 557455aabc3SBrian Somers * XXX this stuff should really live in the FSM. Our config should 558455aabc3SBrian Somers * associate executable sections in files with events. 559455aabc3SBrian Somers */ 560503a7782SBrian Somers if (SelectSystem(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE) < 0) 561455aabc3SBrian Somers if (GetLabel()) { 562455aabc3SBrian Somers if (SelectSystem(fp->bundle, GetLabel(), LINKUPFILE) < 0) 563455aabc3SBrian Somers SelectSystem(fp->bundle, "MYADDR", LINKUPFILE); 564455aabc3SBrian Somers } else 565455aabc3SBrian Somers SelectSystem(fp->bundle, "MYADDR", LINKUPFILE); 566455aabc3SBrian Somers 56783d1af55SBrian Somers throughput_start(&ipcp->throughput); 5681ae349f5Scvs2svn StartIdleTimer(); 56985b542cfSBrian Somers prompt_Display(&prompt, fp->bundle); 5701ae349f5Scvs2svn } 5711ae349f5Scvs2svn 5721ae349f5Scvs2svn void 5731ae349f5Scvs2svn IpcpUp() 5741ae349f5Scvs2svn { 5757308ec68SBrian Somers /* Lower layers are ready.... go */ 5767308ec68SBrian Somers FsmUp(&IpcpInfo.fsm); 5771ae349f5Scvs2svn LogPrintf(LogIPCP, "IPCP Up event!!\n"); 5781ae349f5Scvs2svn } 5791ae349f5Scvs2svn 5801ae349f5Scvs2svn void 5811ae349f5Scvs2svn IpcpOpen() 5821ae349f5Scvs2svn { 5837308ec68SBrian Somers /* Start IPCP please */ 5847308ec68SBrian Somers FsmOpen(&IpcpInfo.fsm); 5851ae349f5Scvs2svn } 5861ae349f5Scvs2svn 5871ae349f5Scvs2svn static int 5881ae349f5Scvs2svn AcceptableAddr(struct in_range *prange, struct in_addr ipaddr) 5891ae349f5Scvs2svn { 5907308ec68SBrian Somers /* Is the given IP in the given range ? */ 5911ae349f5Scvs2svn LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr)); 5921ae349f5Scvs2svn LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr)); 5931ae349f5Scvs2svn LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr)); 5941ae349f5Scvs2svn LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange-> 5951ae349f5Scvs2svn mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr)); 5961ae349f5Scvs2svn return (prange->ipaddr.s_addr & prange->mask.s_addr) == 5971ae349f5Scvs2svn (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 5981ae349f5Scvs2svn } 5991ae349f5Scvs2svn 6001ae349f5Scvs2svn static void 60183d1af55SBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type) 6021ae349f5Scvs2svn { 6037308ec68SBrian Somers /* Deal with incoming PROTO_IPCP */ 604aad81d1eSBrian Somers struct ipcp *ipcp = fsm2ipcp(fp); 6051ae349f5Scvs2svn int type, length; 6061ae349f5Scvs2svn u_long *lp, compproto; 6071ae349f5Scvs2svn struct compreq *pcomp; 6081ae349f5Scvs2svn struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req; 6091ae349f5Scvs2svn char tbuff[100]; 6101ae349f5Scvs2svn char tbuff2[100]; 6111ae349f5Scvs2svn 6121ae349f5Scvs2svn ackp = AckBuff; 6131ae349f5Scvs2svn nakp = NakBuff; 6141ae349f5Scvs2svn rejp = RejBuff; 6151ae349f5Scvs2svn 6161ae349f5Scvs2svn while (plen >= sizeof(struct fsmconfig)) { 6171ae349f5Scvs2svn type = *cp; 6181ae349f5Scvs2svn length = cp[1]; 6191ae349f5Scvs2svn if (type < NCFTYPES) 6201ae349f5Scvs2svn snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); 6211ae349f5Scvs2svn else if (type > 128 && type < 128 + NCFTYPES128) 6221ae349f5Scvs2svn snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length); 6231ae349f5Scvs2svn else 6241ae349f5Scvs2svn snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length); 6251ae349f5Scvs2svn 6261ae349f5Scvs2svn switch (type) { 6271ae349f5Scvs2svn case TY_IPADDR: /* RFC1332 */ 6281ae349f5Scvs2svn lp = (u_long *) (cp + 2); 6291ae349f5Scvs2svn ipaddr.s_addr = *lp; 6301ae349f5Scvs2svn LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 6311ae349f5Scvs2svn 6321ae349f5Scvs2svn switch (mode_type) { 6331ae349f5Scvs2svn case MODE_REQ: 634503a7782SBrian Somers if (iplist_isvalid(&ipcp->cfg.peer_list)) { 6351ae349f5Scvs2svn if (ipaddr.s_addr == INADDR_ANY || 636503a7782SBrian Somers iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || 637503a7782SBrian Somers ipcp_SetIPaddress(fp->bundle, ipcp, ipcp->cfg.my_range.ipaddr, 638455aabc3SBrian Somers ipaddr, ifnetmask, 1)) { 6391ae349f5Scvs2svn LogPrintf(LogIPCP, "%s: Address invalid or already in use\n", 6401ae349f5Scvs2svn inet_ntoa(ipaddr)); 641503a7782SBrian Somers ipcp->peer_ip = ChooseHisAddr 642503a7782SBrian Somers (fp->bundle, ipcp, ipcp->cfg.my_range.ipaddr); 643503a7782SBrian Somers if (ipcp->peer_ip.s_addr == INADDR_ANY) { 6441ae349f5Scvs2svn memcpy(rejp, cp, length); 6451ae349f5Scvs2svn rejp += length; 6461ae349f5Scvs2svn } else { 6471ae349f5Scvs2svn memcpy(nakp, cp, 2); 648503a7782SBrian Somers memcpy(nakp+2, &ipcp->peer_ip.s_addr, length - 2); 6491ae349f5Scvs2svn nakp += length; 6501ae349f5Scvs2svn } 6511ae349f5Scvs2svn break; 6521ae349f5Scvs2svn } 653503a7782SBrian Somers } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { 6541ae349f5Scvs2svn /* 6551ae349f5Scvs2svn * If destination address is not acceptable, insist to use what we 6561ae349f5Scvs2svn * want to use. 6571ae349f5Scvs2svn */ 6581ae349f5Scvs2svn memcpy(nakp, cp, 2); 659503a7782SBrian Somers memcpy(nakp+2, &ipcp->peer_ip.s_addr, length - 2); 6601ae349f5Scvs2svn nakp += length; 6611ae349f5Scvs2svn break; 6621ae349f5Scvs2svn } 663503a7782SBrian Somers ipcp->peer_ip = ipaddr; 6641ae349f5Scvs2svn memcpy(ackp, cp, length); 6651ae349f5Scvs2svn ackp += length; 6661ae349f5Scvs2svn break; 6671ae349f5Scvs2svn case MODE_NAK: 668503a7782SBrian Somers if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { 6691ae349f5Scvs2svn /* Use address suggested by peer */ 6701ae349f5Scvs2svn snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, 671503a7782SBrian Somers inet_ntoa(ipcp->my_ip)); 6721ae349f5Scvs2svn LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 673503a7782SBrian Somers ipcp->my_ip = ipaddr; 6741ae349f5Scvs2svn } else { 6751ae349f5Scvs2svn LogPrintf(LogIPCP, "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); 67683d1af55SBrian Somers FsmClose(&ipcp->fsm); 6771ae349f5Scvs2svn } 6781ae349f5Scvs2svn break; 6791ae349f5Scvs2svn case MODE_REJ: 680503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 6811ae349f5Scvs2svn break; 6821ae349f5Scvs2svn } 6831ae349f5Scvs2svn break; 6841ae349f5Scvs2svn case TY_COMPPROTO: 6851ae349f5Scvs2svn lp = (u_long *) (cp + 2); 6861ae349f5Scvs2svn compproto = htonl(*lp); 6871ae349f5Scvs2svn LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); 6881ae349f5Scvs2svn 6891ae349f5Scvs2svn switch (mode_type) { 6901ae349f5Scvs2svn case MODE_REQ: 6911ae349f5Scvs2svn if (!Acceptable(ConfVjcomp)) { 6921ae349f5Scvs2svn memcpy(rejp, cp, length); 6931ae349f5Scvs2svn rejp += length; 6941ae349f5Scvs2svn } else { 6951ae349f5Scvs2svn pcomp = (struct compreq *) (cp + 2); 6961ae349f5Scvs2svn switch (length) { 6971ae349f5Scvs2svn case 4: /* RFC1172 */ 6981ae349f5Scvs2svn if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 6991ae349f5Scvs2svn LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); 70083d1af55SBrian Somers ipcp->heis1172 = 1; 701503a7782SBrian Somers ipcp->peer_compproto = compproto; 7021ae349f5Scvs2svn memcpy(ackp, cp, length); 7031ae349f5Scvs2svn ackp += length; 7041ae349f5Scvs2svn } else { 7051ae349f5Scvs2svn memcpy(nakp, cp, 2); 7061ae349f5Scvs2svn pcomp->proto = htons(PROTO_VJCOMP); 7071ae349f5Scvs2svn memcpy(nakp+2, &pcomp, 2); 7081ae349f5Scvs2svn nakp += length; 7091ae349f5Scvs2svn } 7101ae349f5Scvs2svn break; 7111ae349f5Scvs2svn case 6: /* RFC1332 */ 7121ae349f5Scvs2svn if (ntohs(pcomp->proto) == PROTO_VJCOMP 713503a7782SBrian Somers && pcomp->slots <= MAX_VJ_STATES 714503a7782SBrian Somers && pcomp->slots >= MIN_VJ_STATES) { 715503a7782SBrian Somers ipcp->peer_compproto = compproto; 71683d1af55SBrian Somers ipcp->heis1172 = 0; 7171ae349f5Scvs2svn memcpy(ackp, cp, length); 7181ae349f5Scvs2svn ackp += length; 7191ae349f5Scvs2svn } else { 7201ae349f5Scvs2svn memcpy(nakp, cp, 2); 7211ae349f5Scvs2svn pcomp->proto = htons(PROTO_VJCOMP); 722503a7782SBrian Somers pcomp->slots = DEF_VJ_STATES; 7231ae349f5Scvs2svn pcomp->compcid = 0; 7241ae349f5Scvs2svn memcpy(nakp+2, &pcomp, sizeof pcomp); 7251ae349f5Scvs2svn nakp += length; 7261ae349f5Scvs2svn } 7271ae349f5Scvs2svn break; 7281ae349f5Scvs2svn default: 7291ae349f5Scvs2svn memcpy(rejp, cp, length); 7301ae349f5Scvs2svn rejp += length; 7311ae349f5Scvs2svn break; 7321ae349f5Scvs2svn } 7331ae349f5Scvs2svn } 7341ae349f5Scvs2svn break; 7351ae349f5Scvs2svn case MODE_NAK: 7361ae349f5Scvs2svn LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n", 737503a7782SBrian Somers tbuff, ipcp->my_compproto, compproto); 738503a7782SBrian Somers ipcp->my_compproto = compproto; 7391ae349f5Scvs2svn break; 7401ae349f5Scvs2svn case MODE_REJ: 741503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 7421ae349f5Scvs2svn break; 7431ae349f5Scvs2svn } 7441ae349f5Scvs2svn break; 7451ae349f5Scvs2svn case TY_IPADDRS: /* RFC1172 */ 7461ae349f5Scvs2svn lp = (u_long *) (cp + 2); 7471ae349f5Scvs2svn ipaddr.s_addr = *lp; 7481ae349f5Scvs2svn lp = (u_long *) (cp + 6); 7491ae349f5Scvs2svn dstipaddr.s_addr = *lp; 7501ae349f5Scvs2svn snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); 7511ae349f5Scvs2svn LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); 7521ae349f5Scvs2svn 7531ae349f5Scvs2svn switch (mode_type) { 7541ae349f5Scvs2svn case MODE_REQ: 755503a7782SBrian Somers ipcp->peer_ip = ipaddr; 756503a7782SBrian Somers ipcp->my_ip = dstipaddr; 7571ae349f5Scvs2svn memcpy(ackp, cp, length); 7581ae349f5Scvs2svn ackp += length; 7591ae349f5Scvs2svn break; 7601ae349f5Scvs2svn case MODE_NAK: 7611ae349f5Scvs2svn snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff, 762503a7782SBrian Somers inet_ntoa(ipcp->my_ip)); 7631ae349f5Scvs2svn LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 764503a7782SBrian Somers ipcp->my_ip = ipaddr; 765503a7782SBrian Somers ipcp->peer_ip = dstipaddr; 7661ae349f5Scvs2svn break; 7671ae349f5Scvs2svn case MODE_REJ: 768503a7782SBrian Somers ipcp->peer_reject |= (1 << type); 7691ae349f5Scvs2svn break; 7701ae349f5Scvs2svn } 7711ae349f5Scvs2svn break; 7721ae349f5Scvs2svn 7731ae349f5Scvs2svn /* 7741ae349f5Scvs2svn * MS extensions for MS's PPP 7751ae349f5Scvs2svn */ 7761ae349f5Scvs2svn 7771ae349f5Scvs2svn #ifndef NOMSEXT 7781ae349f5Scvs2svn case TY_PRIMARY_DNS: /* MS PPP DNS negotiation hack */ 7791ae349f5Scvs2svn case TY_SECONDARY_DNS: 7801ae349f5Scvs2svn if (!Enabled(ConfMSExt)) { 7811ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n"); 78283d1af55SBrian Somers ipcp->my_reject |= (1 << type); 7831ae349f5Scvs2svn memcpy(rejp, cp, length); 7841ae349f5Scvs2svn rejp += length; 7851ae349f5Scvs2svn break; 7861ae349f5Scvs2svn } 7871ae349f5Scvs2svn switch (mode_type) { 7881ae349f5Scvs2svn case MODE_REQ: 7891ae349f5Scvs2svn lp = (u_long *) (cp + 2); 7901ae349f5Scvs2svn dnsstuff.s_addr = *lp; 791503a7782SBrian Somers ms_info_req.s_addr = ipcp->cfg.ns_entries 79229e275ceSBrian Somers [(type - TY_PRIMARY_DNS) ? 1 : 0].s_addr; 7931ae349f5Scvs2svn if (dnsstuff.s_addr != ms_info_req.s_addr) { 7941ae349f5Scvs2svn 7951ae349f5Scvs2svn /* 7961ae349f5Scvs2svn * So the client has got the DNS stuff wrong (first request) so 7971ae349f5Scvs2svn * we'll tell 'em how it is 7981ae349f5Scvs2svn */ 7991ae349f5Scvs2svn memcpy(nakp, cp, 2); /* copy first two (type/length) */ 8001ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n", 8011ae349f5Scvs2svn type, 8021ae349f5Scvs2svn inet_ntoa(dnsstuff), 8031ae349f5Scvs2svn inet_ntoa(ms_info_req)); 8041ae349f5Scvs2svn memcpy(nakp+2, &ms_info_req, length); 8051ae349f5Scvs2svn nakp += length; 8061ae349f5Scvs2svn break; 8071ae349f5Scvs2svn } 8081ae349f5Scvs2svn 8091ae349f5Scvs2svn /* 8101ae349f5Scvs2svn * Otherwise they have it right (this time) so we send a ack packet 8111ae349f5Scvs2svn * back confirming it... end of story 8121ae349f5Scvs2svn */ 8131ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n", 8141ae349f5Scvs2svn type, 8151ae349f5Scvs2svn inet_ntoa(ms_info_req)); 8161ae349f5Scvs2svn memcpy(ackp, cp, length); 8171ae349f5Scvs2svn ackp += length; 8181ae349f5Scvs2svn break; 8191ae349f5Scvs2svn case MODE_NAK: /* what does this mean?? */ 8201ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type); 8211ae349f5Scvs2svn break; 8221ae349f5Scvs2svn case MODE_REJ: /* confused?? me to :) */ 8231ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type); 8241ae349f5Scvs2svn break; 8251ae349f5Scvs2svn } 8261ae349f5Scvs2svn break; 8271ae349f5Scvs2svn 8281ae349f5Scvs2svn case TY_PRIMARY_NBNS: /* MS PPP NetBIOS nameserver hack */ 8291ae349f5Scvs2svn case TY_SECONDARY_NBNS: 8301ae349f5Scvs2svn if (!Enabled(ConfMSExt)) { 8311ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n"); 83283d1af55SBrian Somers ipcp->my_reject |= (1 << type); 8331ae349f5Scvs2svn memcpy(rejp, cp, length); 8341ae349f5Scvs2svn rejp += length; 8351ae349f5Scvs2svn break; 8361ae349f5Scvs2svn } 8371ae349f5Scvs2svn switch (mode_type) { 8381ae349f5Scvs2svn case MODE_REQ: 8391ae349f5Scvs2svn lp = (u_long *) (cp + 2); 8401ae349f5Scvs2svn dnsstuff.s_addr = *lp; 841503a7782SBrian Somers ms_info_req.s_addr = ipcp->cfg.nbns_entries 84229e275ceSBrian Somers [(type - TY_PRIMARY_NBNS) ? 1 : 0].s_addr; 8431ae349f5Scvs2svn if (dnsstuff.s_addr != ms_info_req.s_addr) { 8441ae349f5Scvs2svn memcpy(nakp, cp, 2); 8451ae349f5Scvs2svn memcpy(nakp+2, &ms_info_req.s_addr, length); 8461ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n", 8471ae349f5Scvs2svn type, 8481ae349f5Scvs2svn inet_ntoa(dnsstuff), 8491ae349f5Scvs2svn inet_ntoa(ms_info_req)); 8501ae349f5Scvs2svn nakp += length; 8511ae349f5Scvs2svn break; 8521ae349f5Scvs2svn } 8531ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n", 8541ae349f5Scvs2svn type, 8551ae349f5Scvs2svn inet_ntoa(ms_info_req)); 8561ae349f5Scvs2svn memcpy(ackp, cp, length); 8571ae349f5Scvs2svn ackp += length; 8581ae349f5Scvs2svn break; 8591ae349f5Scvs2svn case MODE_NAK: 8601ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type); 8611ae349f5Scvs2svn break; 8621ae349f5Scvs2svn case MODE_REJ: 8631ae349f5Scvs2svn LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type); 8641ae349f5Scvs2svn break; 8651ae349f5Scvs2svn } 8661ae349f5Scvs2svn break; 8671ae349f5Scvs2svn 8681ae349f5Scvs2svn #endif 8691ae349f5Scvs2svn 8701ae349f5Scvs2svn default: 87183d1af55SBrian Somers ipcp->my_reject |= (1 << type); 8721ae349f5Scvs2svn memcpy(rejp, cp, length); 8731ae349f5Scvs2svn rejp += length; 8741ae349f5Scvs2svn break; 8751ae349f5Scvs2svn } 8761ae349f5Scvs2svn plen -= length; 8771ae349f5Scvs2svn cp += length; 8781ae349f5Scvs2svn } 8791ae349f5Scvs2svn } 8801ae349f5Scvs2svn 8811ae349f5Scvs2svn void 8821ae349f5Scvs2svn IpcpInput(struct mbuf * bp) 8831ae349f5Scvs2svn { 8847308ec68SBrian Somers /* Got PROTO_IPCP from link */ 8857308ec68SBrian Somers FsmInput(&IpcpInfo.fsm, bp); 8861ae349f5Scvs2svn } 8871ae349f5Scvs2svn 8881ae349f5Scvs2svn int 8897a6f8720SBrian Somers UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) 8901ae349f5Scvs2svn { 8917308ec68SBrian Somers /* Use `hisaddr' for the peers address (set iface if `setaddr') */ 892503a7782SBrian Somers memset(&IpcpInfo.cfg.peer_range, '\0', sizeof IpcpInfo.cfg.peer_range); 893503a7782SBrian Somers iplist_reset(&IpcpInfo.cfg.peer_list); 8941ae349f5Scvs2svn if (strpbrk(hisaddr, ",-")) { 895503a7782SBrian Somers iplist_setsrc(&IpcpInfo.cfg.peer_list, hisaddr); 896503a7782SBrian Somers if (iplist_isvalid(&IpcpInfo.cfg.peer_list)) { 897503a7782SBrian Somers iplist_setrandpos(&IpcpInfo.cfg.peer_list); 898503a7782SBrian Somers IpcpInfo.peer_ip = ChooseHisAddr 899503a7782SBrian Somers (bundle, &IpcpInfo, IpcpInfo.my_ip); 900503a7782SBrian Somers if (IpcpInfo.peer_ip.s_addr == INADDR_ANY) { 901503a7782SBrian Somers LogPrintf(LogWARN, "%s: None available !\n", IpcpInfo.cfg.peer_list.src); 9021ae349f5Scvs2svn return(0); 9031ae349f5Scvs2svn } 904503a7782SBrian Somers IpcpInfo.cfg.peer_range.ipaddr.s_addr = IpcpInfo.peer_ip.s_addr; 905503a7782SBrian Somers IpcpInfo.cfg.peer_range.mask.s_addr = INADDR_BROADCAST; 906503a7782SBrian Somers IpcpInfo.cfg.peer_range.width = 32; 9071ae349f5Scvs2svn } else { 9081ae349f5Scvs2svn LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr); 9091ae349f5Scvs2svn return 0; 9101ae349f5Scvs2svn } 911503a7782SBrian Somers } else if (ParseAddr(1, &hisaddr, &IpcpInfo.cfg.peer_range.ipaddr, 912503a7782SBrian Somers &IpcpInfo.cfg.peer_range.mask, 913503a7782SBrian Somers &IpcpInfo.cfg.peer_range.width) != 0) { 914503a7782SBrian Somers IpcpInfo.peer_ip.s_addr = IpcpInfo.cfg.peer_range.ipaddr.s_addr; 9151ae349f5Scvs2svn 916455aabc3SBrian Somers if (setaddr && ipcp_SetIPaddress(bundle, &IpcpInfo, 917503a7782SBrian Somers IpcpInfo.cfg.my_range.ipaddr, 918503a7782SBrian Somers IpcpInfo.cfg.peer_range.ipaddr, ifnetmask, 919455aabc3SBrian Somers 0) < 0) { 920503a7782SBrian Somers IpcpInfo.cfg.my_range.ipaddr.s_addr = INADDR_ANY; 921503a7782SBrian Somers IpcpInfo.cfg.peer_range.ipaddr.s_addr = INADDR_ANY; 9221ae349f5Scvs2svn return 0; 9231ae349f5Scvs2svn } 9241ae349f5Scvs2svn } else 9251ae349f5Scvs2svn return 0; 9261ae349f5Scvs2svn 9271ae349f5Scvs2svn return 1; 9281ae349f5Scvs2svn } 929