ipcp.c revision 15738
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 * 2015738Sphk * $Id: ipcp.c,v 1.7 1996/01/11 17:48:50 phk Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai * o More RFC1772 backwoard compatibility 246059Samurai */ 256059Samurai#include "fsm.h" 266059Samurai#include "lcpproto.h" 276059Samurai#include "lcp.h" 286059Samurai#include "ipcp.h" 296059Samurai#include <netdb.h> 306059Samurai#include <netinet/in_systm.h> 316059Samurai#include <netinet/ip.h> 326059Samurai#include <arpa/inet.h> 336059Samurai#include <sys/socket.h> 346059Samurai#include "slcompress.h" 356059Samurai#include "os.h" 366059Samurai#include "phase.h" 376059Samurai#include "vars.h" 386059Samurai 396059Samuraiextern void PutConfValue(); 406059Samuraiextern void Prompt(); 416059Samuraiextern struct in_addr ifnetmask; 426059Samurai 436059Samuraistruct ipcpstate IpcpInfo; 449440Samuraistruct in_range DefMyAddress, DefHisAddress, DefTriggerAddress; 456059Samurai 466735Samuraistatic void IpcpSendConfigReq __P((struct fsm *)); 476735Samuraistatic void IpcpSendTerminateAck __P((struct fsm *)); 486735Samuraistatic void IpcpSendTerminateReq __P((struct fsm *)); 496735Samuraistatic void IpcpDecodeConfig __P((u_char *, int, int)); 506735Samuraistatic void IpcpLayerStart __P((struct fsm *)); 516735Samuraistatic void IpcpLayerFinish __P((struct fsm *)); 526735Samuraistatic void IpcpLayerUp __P((struct fsm *)); 536735Samuraistatic void IpcpLayerDown __P((struct fsm *)); 546735Samuraistatic void IpcpInitRestartCounter __P((struct fsm *)); 556059Samurai 567001Samuraistruct pppTimer IpcpReportTimer; 576059Samurai 586059Samuraistatic int lastInOctets, lastOutOctets; 596059Samurai 606059Samurai#define REJECTED(p, x) (p->his_reject & (1<<x)) 616059Samurai 626059Samuraistruct fsm IpcpFsm = { 636059Samurai "IPCP", 646059Samurai PROTO_IPCP, 656059Samurai IPCP_MAXCODE, 666059Samurai OPEN_ACTIVE, 676059Samurai ST_INITIAL, 686059Samurai 0, 0, 0, 696059Samurai 706059Samurai 0, 716059Samurai { 0, 0, 0, NULL, NULL, NULL }, 726059Samurai 736059Samurai IpcpLayerUp, 746059Samurai IpcpLayerDown, 756059Samurai IpcpLayerStart, 766059Samurai IpcpLayerFinish, 776059Samurai IpcpInitRestartCounter, 786059Samurai IpcpSendConfigReq, 796059Samurai IpcpSendTerminateReq, 806059Samurai IpcpSendTerminateAck, 816059Samurai IpcpDecodeConfig, 826059Samurai}; 836059Samurai 846059Samuraistatic char *cftypes[] = { 856059Samurai "???", "IPADDRS", "COMPPROTO", "IPADDR", 866059Samurai}; 876059Samurai 886059Samurai/* 896059Samurai * Function called every second. Updates connection period and idle period, 906059Samurai * also update LQR information. 916059Samurai */ 926059Samuraistatic void 936059SamuraiIpcpReportFunc() 946059Samurai{ 956059Samurai ipConnectSecs++; 966059Samurai if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets) 976059Samurai ipIdleSecs++; 986059Samurai lastInOctets = ipInOctets; 996059Samurai lastOutOctets = ipOutOctets; 1006059Samurai StopTimer(&IpcpReportTimer); 1016059Samurai IpcpReportTimer.state = TIMER_STOPPED; 1026059Samurai StartTimer(&IpcpReportTimer); 1036059Samurai} 1046059Samurai 1056059Samuraistatic void 1066059SamuraiIpcpStartReport() 1076059Samurai{ 1086059Samurai ipIdleSecs = ipConnectSecs = 0; 1096059Samurai StopTimer(&IpcpReportTimer); 1106059Samurai IpcpReportTimer.state = TIMER_STOPPED; 1116059Samurai IpcpReportTimer.load = SECTICKS; 1126059Samurai IpcpReportTimer.func = IpcpReportFunc; 1136059Samurai StartTimer(&IpcpReportTimer); 1146059Samurai} 1156059Samurai 1166059Samuraivoid 1176059SamuraiReportIpcpStatus() 1186059Samurai{ 1196059Samurai struct ipcpstate *icp = &IpcpInfo; 1206059Samurai struct fsm *fp = &IpcpFsm; 1216059Samurai 1226059Samurai printf("%s [%s]\n", fp->name, StateNames[fp->state]); 12313389Sphk printf(" his side: %s, %lx\n", 1246059Samurai inet_ntoa(icp->his_ipaddr), icp->his_compproto); 12513389Sphk printf(" my side: %s, %lx\n", 1266059Samurai inet_ntoa(icp->want_ipaddr), icp->want_compproto); 1276059Samurai printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs); 1289440Samurai printf("Defaults:\n"); 1299440Samurai printf(" My Address: %s/%d\n", 1306059Samurai inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width); 1319440Samurai printf(" His Address: %s/%d\n", 1326059Samurai inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width); 1339440Samurai printf(" Negotiation: %s/%d\n", 1349440Samurai inet_ntoa(DefTriggerAddress.ipaddr), DefTriggerAddress.width); 1356059Samurai} 1366059Samurai 1376059Samuraivoid 1386059SamuraiIpcpDefAddress() 1396059Samurai{ 1406059Samurai struct hostent *hp; 1416059Samurai char name[200]; 1426059Samurai 1436059Samurai bzero(&DefMyAddress, sizeof(DefMyAddress)); 1446059Samurai bzero(&DefHisAddress, sizeof(DefHisAddress)); 1459440Samurai bzero(&DefTriggerAddress, sizeof(DefTriggerAddress)); 1466059Samurai if (gethostname(name, sizeof(name)) == 0) { 1476059Samurai hp = gethostbyname(name); 1486059Samurai if (hp && hp->h_addrtype == AF_INET) { 1496059Samurai bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length); 1506059Samurai } 1516059Samurai } 1526059Samurai} 1536059Samurai 1546059Samuraivoid 1556059SamuraiIpcpInit() 1566059Samurai{ 1576059Samurai struct ipcpstate *icp = &IpcpInfo; 1586059Samurai 1596059Samurai FsmInit(&IpcpFsm); 1606059Samurai bzero(icp, sizeof(struct ipcpstate)); 1616059Samurai if ((mode & MODE_DEDICATED) && !dstsystem) { 1626059Samurai icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0; 1636059Samurai } else { 1646059Samurai icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; 1656059Samurai icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; 1666059Samurai } 1679440Samurai 1689440Samurai /* 1699440Samurai * Some implementation of PPP are: 1709440Samurai * Starting a negotiaion by require sending *special* value as my address, 1719440Samurai * even though standard of PPP is defined full negotiation based. 1729440Samurai * (e.g. "0.0.0.0" or Not "0.0.0.0") 1739440Samurai */ 1749440Samurai if ( icp->want_ipaddr.s_addr == 0 ) { 1759440Samurai icp->want_ipaddr.s_addr = DefTriggerAddress.ipaddr.s_addr; 1769440Samurai } 1779440Samurai 1786059Samurai if (Enabled(ConfVjcomp)) 1796059Samurai icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8); 1806059Samurai else 1816059Samurai icp->want_compproto = 0; 1826059Samurai icp->heis1172 = 0; 1836059Samurai IpcpFsm.maxconfig = 10; 1846059Samurai} 1856059Samurai 1866059Samuraistatic void 1876059SamuraiIpcpInitRestartCounter(fp) 1886059Samuraistruct fsm *fp; 1896059Samurai{ 1906735Samurai fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 1916059Samurai fp->restart = 5; 1926059Samurai} 1936059Samurai 1946059Samuraistatic void 1956059SamuraiIpcpSendConfigReq(fp) 1966059Samuraistruct fsm *fp; 1976059Samurai{ 1986059Samurai u_char *cp; 1996059Samurai struct ipcpstate *icp = &IpcpInfo; 2006059Samurai 2016059Samurai cp = ReqBuff; 20215738Sphk LogPrintf(LOG_LCP_BIT, "%s: SendConfigReq\n", fp->name); 2036735Samurai if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR)) 2046735Samurai PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr)); 2056059Samurai if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) { 2066059Samurai if (icp->heis1172) 2076059Samurai PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16); 2086059Samurai else 2096059Samurai PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto); 2106059Samurai } 2116059Samurai FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 2126059Samurai} 2136059Samurai 2146059Samuraistatic void 2156059SamuraiIpcpSendTerminateReq(fp) 2166059Samuraistruct fsm *fp; 2176059Samurai{ 2186059Samurai /* XXX: No code yet */ 2196059Samurai} 2206059Samurai 2216059Samuraistatic void 2226059SamuraiIpcpSendTerminateAck(fp) 2236059Samuraistruct fsm *fp; 2246059Samurai{ 22515738Sphk LogPrintf(LOG_LCP_BIT, " %s: SendTerminateAck\n", fp->name); 2266059Samurai FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 2276059Samurai} 2286059Samurai 2296059Samuraistatic void 2306059SamuraiIpcpLayerStart(fp) 2316059Samuraistruct fsm *fp; 2326059Samurai{ 23315738Sphk LogPrintf(LOG_LCP_BIT, "%s: LayerStart.\n", fp->name); 2346059Samurai} 2356059Samurai 2366059Samuraistatic void 2376059SamuraiIpcpLayerFinish(fp) 2386059Samuraistruct fsm *fp; 2396059Samurai{ 24015738Sphk LogPrintf(LOG_LCP_BIT, "%s: LayerFinish.\n", fp->name); 2416059Samurai LcpClose(); 2426059Samurai NewPhase(PHASE_TERMINATE); 2436059Samurai} 2446059Samurai 2456059Samuraistatic void 2466059SamuraiIpcpLayerDown(fp) 2476059Samuraistruct fsm *fp; 2486059Samurai{ 24915738Sphk LogPrintf(LOG_LCP_BIT, "%s: LayerDown.\n", fp->name); 2506059Samurai StopTimer(&IpcpReportTimer); 2516059Samurai} 2526059Samurai 2536059Samurai/* 2546059Samurai * Called when IPCP has reached to OPEN state 2556059Samurai */ 2566059Samuraistatic void 2576059SamuraiIpcpLayerUp(fp) 2586059Samuraistruct fsm *fp; 2596059Samurai{ 2606059Samurai char tbuff[100]; 2616059Samurai 2626059Samurai#ifdef VERBOSE 2636059Samurai fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state); 2646059Samurai#endif 2656059Samurai Prompt(1); 26615738Sphk LogPrintf(LOG_LCP_BIT, "%s: LayerUp.\n", fp->name); 2676059Samurai sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr)); 26815738Sphk LogPrintf(LOG_LCP_BIT|LOG_LINK_BIT, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); 2696059Samurai OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask); 2706059Samurai OsLinkup(); 2716059Samurai IpcpStartReport(); 2726059Samurai StartIdleTimer(); 2736059Samurai} 2746059Samurai 2756059Samuraivoid 2766059SamuraiIpcpUp() 2776059Samurai{ 2786059Samurai FsmUp(&IpcpFsm); 27915738Sphk LogPrintf(LOG_LCP_BIT, "IPCP Up event!!\n"); 2806059Samurai} 2816059Samurai 2826059Samuraivoid 2836059SamuraiIpcpOpen() 2846059Samurai{ 2856059Samurai FsmOpen(&IpcpFsm); 2866059Samurai} 2876059Samurai 2886059Samuraistatic int 2896059SamuraiAcceptableAddr(prange, ipaddr) 2906059Samuraistruct in_range *prange; 2916059Samuraistruct in_addr ipaddr; 2926059Samurai{ 2936059Samurai#ifdef DEBUG 2946059Samurai logprintf("requested = %x ", htonl(ipaddr.s_addr)); 2956059Samurai logprintf("range = %x", htonl(prange->ipaddr.s_addr)); 2966059Samurai logprintf("/%x\n", htonl(prange->mask.s_addr)); 2976059Samurai logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr), 2986059Samurai htonl(ipaddr.s_addr & prange->mask.s_addr)); 2996059Samurai#endif 3006059Samurai return((prange->ipaddr.s_addr & prange->mask.s_addr) == 3016059Samurai (ipaddr.s_addr & prange->mask.s_addr)); 3026059Samurai} 3036059Samurai 3046059Samuraistatic void 3056735SamuraiIpcpDecodeConfig(cp, plen, mode) 3066735Samuraiu_char *cp; 3076735Samuraiint plen; 3086059Samuraiint mode; 3096059Samurai{ 3106735Samurai int type, length; 3116059Samurai u_long *lp, compproto; 3126059Samurai struct compreq *pcomp; 3136059Samurai struct in_addr ipaddr, dstipaddr; 3146059Samurai char tbuff[100]; 3156059Samurai 3166059Samurai ackp = AckBuff; 3176059Samurai nakp = NakBuff; 3186059Samurai rejp = RejBuff; 3196059Samurai 3206059Samurai while (plen >= sizeof(struct fsmconfig)) { 3216059Samurai if (plen < 0) 3226059Samurai break; 3236059Samurai type = *cp; 3246059Samurai length = cp[1]; 3256059Samurai if (type <= TY_IPADDR) 3266059Samurai sprintf(tbuff, " %s[%d] ", cftypes[type], length); 3276059Samurai else 3286059Samurai sprintf(tbuff, " "); 3296059Samurai 3306059Samurai switch (type) { 3316059Samurai case TY_IPADDR: /* RFC1332 */ 3326059Samurai lp = (u_long *)(cp + 2); 3336059Samurai ipaddr.s_addr = *lp; 33415738Sphk LogPrintf(LOG_LCP_BIT, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 3356059Samurai 3366059Samurai switch (mode) { 3376059Samurai case MODE_REQ: 3386059Samurai if (!AcceptableAddr(&DefHisAddress, ipaddr)) { 3396059Samurai /* 3406059Samurai * If destination address is not acceptable, insist to use 3416059Samurai * what we want to use. 3426059Samurai */ 3436059Samurai bcopy(cp, nakp, 2); 3446059Samurai bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length); 3456059Samurai nakp += length; 3466059Samurai break; 3478857Srgrimes 3486059Samurai } 3496059Samurai IpcpInfo.his_ipaddr = ipaddr; 3506059Samurai bcopy(cp, ackp, length); 3516059Samurai ackp += length; 3526059Samurai break; 3536059Samurai case MODE_NAK: 3546059Samurai if (AcceptableAddr(&DefMyAddress, ipaddr)) { 3556059Samurai /* 3566059Samurai * Use address suggested by peer. 3576059Samurai */ 3586059Samurai sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 35915738Sphk LogPrintf(LOG_LCP_BIT, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr)); 3606059Samurai IpcpInfo.want_ipaddr = ipaddr; 3616059Samurai } 3626059Samurai break; 3636059Samurai case MODE_REJ: 3646059Samurai IpcpInfo.his_reject |= (1 << type); 3656059Samurai break; 3666059Samurai } 3676059Samurai break; 3686059Samurai case TY_COMPPROTO: 3696059Samurai lp = (u_long *)(cp + 2); 3706059Samurai compproto = htonl(*lp); 37115738Sphk LogPrintf(LOG_LCP_BIT, "%s %08x\n", tbuff, compproto); 3726059Samurai 3736059Samurai switch (mode) { 3746059Samurai case MODE_REQ: 3756059Samurai if (!Acceptable(ConfVjcomp)) { 3766059Samurai bcopy(cp, rejp, length); 3776059Samurai rejp += length; 3786059Samurai } else { 3796059Samurai pcomp = (struct compreq *)(cp + 2); 3806059Samurai switch (length) { 3816059Samurai case 4: /* RFC1172 */ 3826059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 3836059Samurai logprintf("** Peer is speaking RFC1172 compression protocol **\n"); 3846059Samurai IpcpInfo.heis1172 = 1; 3856059Samurai IpcpInfo.his_compproto = compproto; 3866059Samurai bcopy(cp, ackp, length); 3876059Samurai ackp += length; 3886059Samurai } else { 3896059Samurai bcopy(cp, nakp, 2); 3906059Samurai pcomp->proto = htons(PROTO_VJCOMP); 3916059Samurai bcopy(&pcomp, nakp + 2, 2); 3926059Samurai nakp += length; 3936059Samurai } 3946059Samurai break; 3956059Samurai case 6: /* RFC1332 */ 3966059Samurai if (ntohs(pcomp->proto) == PROTO_VJCOMP 3976059Samurai && pcomp->slots < MAX_STATES && pcomp->slots > 2) { 3986059Samurai IpcpInfo.his_compproto = compproto; 3996059Samurai IpcpInfo.heis1172 = 0; 4006059Samurai bcopy(cp, ackp, length); 4016059Samurai ackp += length; 4026059Samurai } else { 4036059Samurai bcopy(cp, nakp, 2); 4046059Samurai pcomp->proto = htons(PROTO_VJCOMP); 4056059Samurai pcomp->slots = MAX_STATES - 1; 4066059Samurai pcomp->compcid = 0; 4076059Samurai bcopy(&pcomp, nakp + 2, sizeof(pcomp)); 4086059Samurai nakp += length; 4096059Samurai } 4106059Samurai break; 4116059Samurai default: 4126059Samurai bcopy(cp, rejp, length); 4136059Samurai rejp += length; 4146059Samurai break; 4156059Samurai } 4166059Samurai } 4176059Samurai break; 4186059Samurai case MODE_NAK: 41915738Sphk LogPrintf(LOG_LCP_BIT, "%s changing compproto: %08x --> %08x\n", 4206059Samurai tbuff, IpcpInfo.want_compproto, compproto); 4216059Samurai IpcpInfo.want_compproto = compproto; 4226059Samurai break; 4236059Samurai case MODE_REJ: 4246059Samurai IpcpInfo.his_reject |= (1 << type); 4256059Samurai break; 4266059Samurai } 4276059Samurai break; 4286059Samurai case TY_IPADDRS: /* RFC1172 */ 4296059Samurai lp = (u_long *)(cp + 2); 4306059Samurai ipaddr.s_addr = *lp; 4316059Samurai lp = (u_long *)(cp + 6); 4326059Samurai dstipaddr.s_addr = *lp; 43315738Sphk LogPrintf(LOG_LCP_BIT, "%s %s, ", tbuff, inet_ntoa(ipaddr)); 43415738Sphk LogPrintf(LOG_LCP_BIT, "%s\n", inet_ntoa(dstipaddr)); 4356059Samurai 4366059Samurai switch (mode) { 4376059Samurai case MODE_REQ: 4386059Samurai IpcpInfo.his_ipaddr = ipaddr; 4396059Samurai IpcpInfo.want_ipaddr = dstipaddr; 4406059Samurai bcopy(cp, ackp, length); 4416059Samurai ackp += length; 4426059Samurai break; 4436059Samurai case MODE_NAK: 44415738Sphk LogPrintf(LOG_LCP_BIT, "%s changing address: %s ", 4456059Samurai tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 44615738Sphk LogPrintf(LOG_LCP_BIT, "--> %s\n", inet_ntoa(ipaddr)); 4476059Samurai IpcpInfo.want_ipaddr = ipaddr; 4486059Samurai IpcpInfo.his_ipaddr = dstipaddr; 4496059Samurai break; 4506059Samurai case MODE_REJ: 4516059Samurai IpcpInfo.his_reject |= (1 << type); 4526059Samurai break; 4536059Samurai } 4546059Samurai break; 4556059Samurai default: 4566059Samurai IpcpInfo.my_reject |= (1 << type); 4576059Samurai bcopy(cp, rejp, length); 4586059Samurai rejp += length; 4596059Samurai break; 4606059Samurai } 4616059Samurai plen -= length; 4626059Samurai cp += length; 4636059Samurai } 4646059Samurai} 4656059Samurai 4666059Samuraivoid 4676059SamuraiIpcpInput(struct mbuf *bp) 4686059Samurai{ 4696059Samurai FsmInput(&IpcpFsm, bp); 4706059Samurai} 471