ipcp.c revision 7001
1100206Sdd/* 2100206Sdd * PPP IP Control Protocol (IPCP) Module 3100206Sdd * 4100206Sdd * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5100206Sdd * 6100206Sdd * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7100206Sdd * 8100206Sdd * Redistribution and use in source and binary forms are permitted 9100206Sdd * provided that the above copyright notice and this paragraph are 10100206Sdd * duplicated in all such forms and that any documentation, 11100206Sdd * advertising materials, and other materials related to such 12100206Sdd * distribution and use acknowledge that the software was developed 13100206Sdd * by the Internet Initiative Japan, Inc. The name of the 14100206Sdd * IIJ may not be used to endorse or promote products derived 15100206Sdd * from this software without specific prior written permission. 16100206Sdd * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17100206Sdd * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18100206Sdd * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19100206Sdd * 20100206Sdd * $Id: ipcp.c,v 1.2 1995/02/26 12:17:33 amurai Exp $ 21100206Sdd * 22100206Sdd * TODO: 23100206Sdd * o More RFC1772 backwoard compatibility 24100206Sdd */ 25100206Sdd#include "fsm.h" 26100206Sdd#include "lcpproto.h" 27100206Sdd#include "lcp.h" 28100206Sdd#include "ipcp.h" 29100206Sdd#include <netdb.h> 30100206Sdd#include <netinet/in_systm.h> 31100206Sdd#include <netinet/ip.h> 32100206Sdd#include <arpa/inet.h> 33100206Sdd#include <sys/socket.h> 34100206Sdd#include "slcompress.h" 35100206Sdd#include "os.h" 36100206Sdd#include "phase.h" 37100206Sdd#include "vars.h" 38100799Sdd 39100206Sddextern void PutConfValue(); 40100206Sddextern void Prompt(); 41100206Sddextern struct in_addr ifnetmask; 42100206Sdd 43100206Sddstruct ipcpstate IpcpInfo; 44100206Sddstruct in_range DefMyAddress, DefHisAddress; 45100206Sdd 46100206Sddstatic void IpcpSendConfigReq __P((struct fsm *)); 47100206Sddstatic void IpcpSendTerminateAck __P((struct fsm *)); 48100206Sddstatic void IpcpSendTerminateReq __P((struct fsm *)); 49100206Sddstatic void IpcpDecodeConfig __P((u_char *, int, int)); 50100803Sddstatic void IpcpLayerStart __P((struct fsm *)); 51100799Sddstatic void IpcpLayerFinish __P((struct fsm *)); 52100799Sddstatic void IpcpLayerUp __P((struct fsm *)); 53100206Sddstatic void IpcpLayerDown __P((struct fsm *)); 54100206Sddstatic void IpcpInitRestartCounter __P((struct fsm *)); 55100206Sdd 56100206Sddstruct pppTimer IpcpReportTimer; 57100206Sdd 58100206Sddstatic int lastInOctets, lastOutOctets; 59100206Sdd 60100206Sdd#define REJECTED(p, x) (p->his_reject & (1<<x)) 61100206Sdd 62100206Sddstruct fsm IpcpFsm = { 63100206Sdd "IPCP", 64100206Sdd PROTO_IPCP, 65100206Sdd IPCP_MAXCODE, 66100206Sdd OPEN_ACTIVE, 67100206Sdd ST_INITIAL, 68100206Sdd 0, 0, 0, 69100206Sdd 70100206Sdd 0, 71100206Sdd { 0, 0, 0, NULL, NULL, NULL }, 72100206Sdd 73100206Sdd IpcpLayerUp, 74100206Sdd IpcpLayerDown, 75100206Sdd IpcpLayerStart, 76100206Sdd IpcpLayerFinish, 77100206Sdd IpcpInitRestartCounter, 78100206Sdd IpcpSendConfigReq, 79100206Sdd IpcpSendTerminateReq, 80100206Sdd IpcpSendTerminateAck, 81100206Sdd IpcpDecodeConfig, 82100206Sdd}; 83100206Sdd 84100206Sddstatic char *cftypes[] = { 85124830Sgrehan "???", "IPADDRS", "COMPPROTO", "IPADDR", 86100206Sdd}; 87100206Sdd 88100206Sdd/* 89100206Sdd * Function called every second. Updates connection period and idle period, 90100206Sdd * also update LQR information. 91100206Sdd */ 92100206Sddstatic void 93100206SddIpcpReportFunc() 94100206Sdd{ 95100206Sdd ipConnectSecs++; 96100206Sdd if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets) 97100206Sdd ipIdleSecs++; 98100206Sdd lastInOctets = ipInOctets; 99100206Sdd lastOutOctets = ipOutOctets; 100100206Sdd StopTimer(&IpcpReportTimer); 101100206Sdd IpcpReportTimer.state = TIMER_STOPPED; 102100206Sdd StartTimer(&IpcpReportTimer); 103100206Sdd} 104100206Sdd 105100206Sddstatic void 106100206SddIpcpStartReport() 107100206Sdd{ 108100206Sdd ipIdleSecs = ipConnectSecs = 0; 109100206Sdd StopTimer(&IpcpReportTimer); 110100206Sdd IpcpReportTimer.state = TIMER_STOPPED; 111100206Sdd IpcpReportTimer.load = SECTICKS; 112100206Sdd IpcpReportTimer.func = IpcpReportFunc; 113100206Sdd StartTimer(&IpcpReportTimer); 114100206Sdd} 115100206Sdd 116100799Sddvoid 117100799SddReportIpcpStatus() 118100799Sdd{ 119100799Sdd struct ipcpstate *icp = &IpcpInfo; 120100799Sdd struct fsm *fp = &IpcpFsm; 121100799Sdd 122100799Sdd printf("%s [%s]\n", fp->name, StateNames[fp->state]); 123100799Sdd printf(" his side: %s, %x\n", 124100206Sdd inet_ntoa(icp->his_ipaddr), icp->his_compproto); 125100206Sdd printf(" my side: %s, %x\n", 126100206Sdd inet_ntoa(icp->want_ipaddr), icp->want_compproto); 127100206Sdd printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs); 128100206Sdd printf("Defaults: My Address: %s/%d ", 129100206Sdd inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width); 130100206Sdd printf("His Address: %s/%d\n", 131100206Sdd inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width); 132100206Sdd} 133100206Sdd 134100206Sddvoid 135100206SddIpcpDefAddress() 136100206Sdd{ 137100206Sdd struct hostent *hp; 138100799Sdd char name[200]; 139100799Sdd 140100799Sdd bzero(&DefMyAddress, sizeof(DefMyAddress)); 141100799Sdd bzero(&DefHisAddress, sizeof(DefHisAddress)); 142100799Sdd if (gethostname(name, sizeof(name)) == 0) { 143100799Sdd hp = gethostbyname(name); 144100799Sdd if (hp && hp->h_addrtype == AF_INET) { 145100799Sdd bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length); 146100206Sdd } 147100206Sdd } 148100206Sdd} 149100206Sdd 150100206Sddvoid 151100206SddIpcpInit() 152100206Sdd{ 153100206Sdd struct ipcpstate *icp = &IpcpInfo; 154100206Sdd 155100206Sdd FsmInit(&IpcpFsm); 156100206Sdd bzero(icp, sizeof(struct ipcpstate)); 157100206Sdd if ((mode & MODE_DEDICATED) && !dstsystem) { 158100206Sdd icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0; 159100206Sdd } else { 160100206Sdd icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; 161100206Sdd icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; 162100206Sdd } 163100206Sdd if (icp->want_ipaddr.s_addr == 0) 164100206Sdd icp->want_ipaddr.s_addr = htonl(0xc0000001); 165100206Sdd if (Enabled(ConfVjcomp)) 166100206Sdd icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8); 167100206Sdd else 168100206Sdd icp->want_compproto = 0; 169100206Sdd icp->heis1172 = 0; 170100206Sdd IpcpFsm.maxconfig = 10; 171100206Sdd} 172100206Sdd 173100206Sddstatic void 174100206SddIpcpInitRestartCounter(fp) 175100206Sddstruct fsm *fp; 176100206Sdd{ 177100206Sdd fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 178100206Sdd fp->restart = 5; 179100206Sdd} 180100206Sdd 181100206Sddstatic void 182100206SddIpcpSendConfigReq(fp) 183100206Sddstruct fsm *fp; 184100206Sdd{ 185100206Sdd u_char *cp; 186100206Sdd struct ipcpstate *icp = &IpcpInfo; 187100206Sdd 188100206Sdd cp = ReqBuff; 189100206Sdd LogPrintf(LOG_LCP, "%s: SendConfigReq\n", fp->name); 190100206Sdd if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR)) 191100206Sdd PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr)); 192100206Sdd if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) { 193100206Sdd if (icp->heis1172) 194100206Sdd PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16); 195100206Sdd else 196100206Sdd PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto); 197100206Sdd } 198100206Sdd FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 199100206Sdd} 200100206Sdd 201100206Sddstatic void 202100206SddIpcpSendTerminateReq(fp) 203100206Sddstruct fsm *fp; 204100206Sdd{ 205100206Sdd /* XXX: No code yet */ 206100206Sdd} 207100206Sdd 208100206Sddstatic void 209100206SddIpcpSendTerminateAck(fp) 210100206Sddstruct fsm *fp; 211100206Sdd{ 212100206Sdd LogPrintf(LOG_LCP, " %s: SendTerminateAck\n", fp->name); 213100206Sdd FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 214100206Sdd} 215100206Sdd 216100206Sddstatic void 217100206SddIpcpLayerStart(fp) 218100206Sddstruct fsm *fp; 219100206Sdd{ 220100206Sdd LogPrintf(LOG_LCP, "%s: LayerStart.\n", fp->name); 221100206Sdd} 222100206Sdd 223100206Sddstatic void 224100206SddIpcpLayerFinish(fp) 225100206Sddstruct fsm *fp; 226100206Sdd{ 227100206Sdd LogPrintf(LOG_LCP, "%s: LayerFinish.\n", fp->name); 228100206Sdd LcpClose(); 229100805Sdd NewPhase(PHASE_TERMINATE); 230100206Sdd} 231100206Sdd 232100206Sddstatic void 233100206SddIpcpLayerDown(fp) 234100206Sddstruct fsm *fp; 235100206Sdd{ 236100206Sdd LogPrintf(LOG_LCP, "%s: LayerDown.\n", fp->name); 237100206Sdd StopTimer(&IpcpReportTimer); 238100206Sdd} 239100206Sdd 240100206Sdd/* 241100206Sdd * Called when IPCP has reached to OPEN state 242100206Sdd */ 243100206Sddstatic void 244100206SddIpcpLayerUp(fp) 245100206Sddstruct fsm *fp; 246100206Sdd{ 247100206Sdd char tbuff[100]; 248100206Sdd 249100206Sdd#ifdef VERBOSE 250100206Sdd fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state); 251100206Sdd#endif 252100206Sdd Prompt(1); 253100206Sdd LogPrintf(LOG_LCP, "%s: LayerUp.\n", fp->name); 254100206Sdd sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr)); 255100206Sdd LogPrintf(LOG_LCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); 256100206Sdd OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask); 257100206Sdd OsLinkup(); 258100206Sdd IpcpStartReport(); 259100206Sdd StartIdleTimer(); 260100206Sdd} 261100206Sdd 262100206Sddvoid 263100206SddIpcpUp() 264100799Sdd{ 265100799Sdd FsmUp(&IpcpFsm); 266100799Sdd LogPrintf(LOG_LCP, "IPCP Up event!!\n"); 267100799Sdd} 268100799Sdd 269100799Sddvoid 270100799SddIpcpOpen() 271100803Sdd{ 272100799Sdd FsmOpen(&IpcpFsm); 273100799Sdd} 274100799Sdd 275100799Sddstatic int 276100799SddAcceptableAddr(prange, ipaddr) 277100799Sddstruct in_range *prange; 278100799Sddstruct in_addr ipaddr; 279100799Sdd{ 280100803Sdd#ifdef DEBUG 281100799Sdd logprintf("requested = %x ", htonl(ipaddr.s_addr)); 282100799Sdd logprintf("range = %x", htonl(prange->ipaddr.s_addr)); 283100799Sdd logprintf("/%x\n", htonl(prange->mask.s_addr)); 284100799Sdd logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr), 285100799Sdd htonl(ipaddr.s_addr & prange->mask.s_addr)); 286100799Sdd#endif 287100799Sdd return((prange->ipaddr.s_addr & prange->mask.s_addr) == 288100799Sdd (ipaddr.s_addr & prange->mask.s_addr)); 289100799Sdd} 290100799Sdd 291100799Sddstatic void 292100799SddIpcpDecodeConfig(cp, plen, mode) 293100799Sddu_char *cp; 294100799Sddint plen; 295100799Sddint mode; 296100799Sdd{ 297100799Sdd int type, length; 298100799Sdd u_long *lp, compproto; 299100799Sdd struct compreq *pcomp; 300100799Sdd struct in_addr ipaddr, dstipaddr; 301100799Sdd char tbuff[100]; 302100799Sdd 303100799Sdd ackp = AckBuff; 304100799Sdd nakp = NakBuff; 305100799Sdd rejp = RejBuff; 306100799Sdd 307100206Sdd while (plen >= sizeof(struct fsmconfig)) { 308100206Sdd if (plen < 0) 309100206Sdd break; 310100206Sdd type = *cp; 311100206Sdd length = cp[1]; 312100206Sdd if (type <= TY_IPADDR) 313100206Sdd sprintf(tbuff, " %s[%d] ", cftypes[type], length); 314100206Sdd else 315100206Sdd sprintf(tbuff, " "); 316100206Sdd 317100206Sdd switch (type) { 318100206Sdd case TY_IPADDR: /* RFC1332 */ 319100206Sdd lp = (u_long *)(cp + 2); 320100206Sdd ipaddr.s_addr = *lp; 321100206Sdd LogPrintf(LOG_LCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 322100206Sdd 323100206Sdd switch (mode) { 324100206Sdd case MODE_REQ: 325100206Sdd if (!AcceptableAddr(&DefHisAddress, ipaddr)) { 326100206Sdd /* 327100206Sdd * If destination address is not acceptable, insist to use 328100206Sdd * what we want to use. 329100206Sdd */ 330100206Sdd bcopy(cp, nakp, 2); 331100206Sdd bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length); 332100206Sdd nakp += length; 333100206Sdd break; 334100206Sdd 335100206Sdd } 336100206Sdd IpcpInfo.his_ipaddr = ipaddr; 337100206Sdd bcopy(cp, ackp, length); 338100206Sdd ackp += length; 339100206Sdd break; 340100206Sdd case MODE_NAK: 341100206Sdd if (AcceptableAddr(&DefMyAddress, ipaddr)) { 342100206Sdd /* 343100206Sdd * Use address suggested by peer. 344100206Sdd */ 345100206Sdd sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 346100206Sdd LogPrintf(LOG_LCP, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr)); 347100206Sdd IpcpInfo.want_ipaddr = ipaddr; 348100206Sdd } 349100206Sdd break; 350100206Sdd case MODE_REJ: 351100206Sdd IpcpInfo.his_reject |= (1 << type); 352100206Sdd break; 353100206Sdd } 354100206Sdd break; 355100206Sdd case TY_COMPPROTO: 356100206Sdd lp = (u_long *)(cp + 2); 357100206Sdd compproto = htonl(*lp); 358100206Sdd LogPrintf(LOG_LCP, "%s %08x\n", tbuff, compproto); 359100206Sdd 360100206Sdd switch (mode) { 361100206Sdd case MODE_REQ: 362100206Sdd if (!Acceptable(ConfVjcomp)) { 363100206Sdd bcopy(cp, rejp, length); 364100206Sdd rejp += length; 365100206Sdd } else { 366100206Sdd pcomp = (struct compreq *)(cp + 2); 367100206Sdd switch (length) { 368100206Sdd case 4: /* RFC1172 */ 369100206Sdd if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 370100206Sdd logprintf("** Peer is speaking RFC1172 compression protocol **\n"); 371100206Sdd IpcpInfo.heis1172 = 1; 372100206Sdd IpcpInfo.his_compproto = compproto; 373100206Sdd bcopy(cp, ackp, length); 374100206Sdd ackp += length; 375100206Sdd } else { 376100206Sdd bcopy(cp, nakp, 2); 377100206Sdd pcomp->proto = htons(PROTO_VJCOMP); 378100206Sdd bcopy(&pcomp, nakp + 2, 2); 379100206Sdd nakp += length; 380100206Sdd } 381100206Sdd break; 382100206Sdd case 6: /* RFC1332 */ 383100206Sdd if (ntohs(pcomp->proto) == PROTO_VJCOMP 384100206Sdd && pcomp->slots < MAX_STATES && pcomp->slots > 2) { 385100206Sdd IpcpInfo.his_compproto = compproto; 386100206Sdd IpcpInfo.heis1172 = 0; 387100206Sdd bcopy(cp, ackp, length); 388100206Sdd ackp += length; 389100206Sdd } else { 390100206Sdd bcopy(cp, nakp, 2); 391100206Sdd pcomp->proto = htons(PROTO_VJCOMP); 392100206Sdd pcomp->slots = MAX_STATES - 1; 393100206Sdd pcomp->compcid = 0; 394100206Sdd bcopy(&pcomp, nakp + 2, sizeof(pcomp)); 395100206Sdd nakp += length; 396100206Sdd } 397100206Sdd break; 398100206Sdd default: 399100206Sdd bcopy(cp, rejp, length); 400100206Sdd rejp += length; 401100206Sdd break; 402100206Sdd } 403100206Sdd } 404100206Sdd break; 405100206Sdd case MODE_NAK: 406100206Sdd LogPrintf(LOG_LCP, "%s changing compproto: %08x --> %08x\n", 407100206Sdd tbuff, IpcpInfo.want_compproto, compproto); 408100206Sdd IpcpInfo.want_compproto = compproto; 409100206Sdd break; 410100206Sdd case MODE_REJ: 411100206Sdd IpcpInfo.his_reject |= (1 << type); 412100206Sdd break; 413100206Sdd } 414100206Sdd break; 415100206Sdd case TY_IPADDRS: /* RFC1172 */ 416100206Sdd lp = (u_long *)(cp + 2); 417100206Sdd ipaddr.s_addr = *lp; 418100206Sdd lp = (u_long *)(cp + 6); 419100206Sdd dstipaddr.s_addr = *lp; 420100206Sdd LogPrintf(LOG_LCP, "%s %s, ", tbuff, inet_ntoa(ipaddr)); 421100206Sdd LogPrintf(LOG_LCP, "%s\n", inet_ntoa(dstipaddr)); 422100206Sdd 423100206Sdd switch (mode) { 424100206Sdd case MODE_REQ: 425100206Sdd IpcpInfo.his_ipaddr = ipaddr; 426100206Sdd IpcpInfo.want_ipaddr = dstipaddr; 427100206Sdd bcopy(cp, ackp, length); 428100206Sdd ackp += length; 429100206Sdd break; 430100206Sdd case MODE_NAK: 431100206Sdd LogPrintf(LOG_LCP, "%s changing address: %s ", 432100206Sdd tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 433100206Sdd LogPrintf(LOG_LCP, "--> %s\n", inet_ntoa(ipaddr)); 434100206Sdd IpcpInfo.want_ipaddr = ipaddr; 435100206Sdd IpcpInfo.his_ipaddr = dstipaddr; 436100206Sdd break; 437100206Sdd case MODE_REJ: 438100206Sdd IpcpInfo.his_reject |= (1 << type); 439100206Sdd break; 440100206Sdd } 441100206Sdd break; 442100206Sdd default: 443100206Sdd IpcpInfo.my_reject |= (1 << type); 444100206Sdd bcopy(cp, rejp, length); 445100206Sdd rejp += length; 446100206Sdd break; 447100206Sdd } 448100206Sdd plen -= length; 449100206Sdd cp += length; 450100206Sdd } 451100206Sdd} 452100206Sdd 453100206Sddvoid 454100206SddIpcpInput(struct mbuf *bp) 455100206Sdd{ 456100206Sdd FsmInput(&IpcpFsm, bp); 457100206Sdd} 458100206Sdd