1 /* 2 * PPP IP Control Protocol (IPCP) Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: ipcp.c,v 1.5 1995/07/04 02:57:11 davidg Exp $ 21 * 22 * TODO: 23 * o More RFC1772 backwoard compatibility 24 */ 25 #include "fsm.h" 26 #include "lcpproto.h" 27 #include "lcp.h" 28 #include "ipcp.h" 29 #include <netdb.h> 30 #include <netinet/in_systm.h> 31 #include <netinet/ip.h> 32 #include <arpa/inet.h> 33 #include <sys/socket.h> 34 #include "slcompress.h" 35 #include "os.h" 36 #include "phase.h" 37 #include "vars.h" 38 39 extern void PutConfValue(); 40 extern void Prompt(); 41 extern struct in_addr ifnetmask; 42 43 struct ipcpstate IpcpInfo; 44 struct in_range DefMyAddress, DefHisAddress, DefTriggerAddress; 45 46 static void IpcpSendConfigReq __P((struct fsm *)); 47 static void IpcpSendTerminateAck __P((struct fsm *)); 48 static void IpcpSendTerminateReq __P((struct fsm *)); 49 static void IpcpDecodeConfig __P((u_char *, int, int)); 50 static void IpcpLayerStart __P((struct fsm *)); 51 static void IpcpLayerFinish __P((struct fsm *)); 52 static void IpcpLayerUp __P((struct fsm *)); 53 static void IpcpLayerDown __P((struct fsm *)); 54 static void IpcpInitRestartCounter __P((struct fsm *)); 55 56 struct pppTimer IpcpReportTimer; 57 58 static int lastInOctets, lastOutOctets; 59 60 #define REJECTED(p, x) (p->his_reject & (1<<x)) 61 62 struct fsm IpcpFsm = { 63 "IPCP", 64 PROTO_IPCP, 65 IPCP_MAXCODE, 66 OPEN_ACTIVE, 67 ST_INITIAL, 68 0, 0, 0, 69 70 0, 71 { 0, 0, 0, NULL, NULL, NULL }, 72 73 IpcpLayerUp, 74 IpcpLayerDown, 75 IpcpLayerStart, 76 IpcpLayerFinish, 77 IpcpInitRestartCounter, 78 IpcpSendConfigReq, 79 IpcpSendTerminateReq, 80 IpcpSendTerminateAck, 81 IpcpDecodeConfig, 82 }; 83 84 static char *cftypes[] = { 85 "???", "IPADDRS", "COMPPROTO", "IPADDR", 86 }; 87 88 /* 89 * Function called every second. Updates connection period and idle period, 90 * also update LQR information. 91 */ 92 static void 93 IpcpReportFunc() 94 { 95 ipConnectSecs++; 96 if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets) 97 ipIdleSecs++; 98 lastInOctets = ipInOctets; 99 lastOutOctets = ipOutOctets; 100 StopTimer(&IpcpReportTimer); 101 IpcpReportTimer.state = TIMER_STOPPED; 102 StartTimer(&IpcpReportTimer); 103 } 104 105 static void 106 IpcpStartReport() 107 { 108 ipIdleSecs = ipConnectSecs = 0; 109 StopTimer(&IpcpReportTimer); 110 IpcpReportTimer.state = TIMER_STOPPED; 111 IpcpReportTimer.load = SECTICKS; 112 IpcpReportTimer.func = IpcpReportFunc; 113 StartTimer(&IpcpReportTimer); 114 } 115 116 void 117 ReportIpcpStatus() 118 { 119 struct ipcpstate *icp = &IpcpInfo; 120 struct fsm *fp = &IpcpFsm; 121 122 printf("%s [%s]\n", fp->name, StateNames[fp->state]); 123 printf(" his side: %s, %x\n", 124 inet_ntoa(icp->his_ipaddr), icp->his_compproto); 125 printf(" my side: %s, %x\n", 126 inet_ntoa(icp->want_ipaddr), icp->want_compproto); 127 printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs); 128 printf("Defaults:\n"); 129 printf(" My Address: %s/%d\n", 130 inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width); 131 printf(" His Address: %s/%d\n", 132 inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width); 133 printf(" Negotiation: %s/%d\n", 134 inet_ntoa(DefTriggerAddress.ipaddr), DefTriggerAddress.width); 135 } 136 137 void 138 IpcpDefAddress() 139 { 140 struct hostent *hp; 141 char name[200]; 142 143 bzero(&DefMyAddress, sizeof(DefMyAddress)); 144 bzero(&DefHisAddress, sizeof(DefHisAddress)); 145 bzero(&DefTriggerAddress, sizeof(DefTriggerAddress)); 146 if (gethostname(name, sizeof(name)) == 0) { 147 hp = gethostbyname(name); 148 if (hp && hp->h_addrtype == AF_INET) { 149 bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length); 150 } 151 } 152 } 153 154 void 155 IpcpInit() 156 { 157 struct ipcpstate *icp = &IpcpInfo; 158 159 FsmInit(&IpcpFsm); 160 bzero(icp, sizeof(struct ipcpstate)); 161 if ((mode & MODE_DEDICATED) && !dstsystem) { 162 icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0; 163 } else { 164 icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; 165 icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; 166 } 167 168 /* 169 * Some implementation of PPP are: 170 * Starting a negotiaion by require sending *special* value as my address, 171 * even though standard of PPP is defined full negotiation based. 172 * (e.g. "0.0.0.0" or Not "0.0.0.0") 173 */ 174 if ( icp->want_ipaddr.s_addr == 0 ) { 175 icp->want_ipaddr.s_addr = DefTriggerAddress.ipaddr.s_addr; 176 } 177 178 if (Enabled(ConfVjcomp)) 179 icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8); 180 else 181 icp->want_compproto = 0; 182 icp->heis1172 = 0; 183 IpcpFsm.maxconfig = 10; 184 } 185 186 static void 187 IpcpInitRestartCounter(fp) 188 struct fsm *fp; 189 { 190 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 191 fp->restart = 5; 192 } 193 194 static void 195 IpcpSendConfigReq(fp) 196 struct fsm *fp; 197 { 198 u_char *cp; 199 struct ipcpstate *icp = &IpcpInfo; 200 201 cp = ReqBuff; 202 LogPrintf(LOG_LCP, "%s: SendConfigReq\n", fp->name); 203 if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR)) 204 PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr)); 205 if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) { 206 if (icp->heis1172) 207 PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16); 208 else 209 PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto); 210 } 211 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 212 } 213 214 static void 215 IpcpSendTerminateReq(fp) 216 struct fsm *fp; 217 { 218 /* XXX: No code yet */ 219 } 220 221 static void 222 IpcpSendTerminateAck(fp) 223 struct fsm *fp; 224 { 225 LogPrintf(LOG_LCP, " %s: SendTerminateAck\n", fp->name); 226 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 227 } 228 229 static void 230 IpcpLayerStart(fp) 231 struct fsm *fp; 232 { 233 LogPrintf(LOG_LCP, "%s: LayerStart.\n", fp->name); 234 } 235 236 static void 237 IpcpLayerFinish(fp) 238 struct fsm *fp; 239 { 240 LogPrintf(LOG_LCP, "%s: LayerFinish.\n", fp->name); 241 LcpClose(); 242 NewPhase(PHASE_TERMINATE); 243 } 244 245 static void 246 IpcpLayerDown(fp) 247 struct fsm *fp; 248 { 249 LogPrintf(LOG_LCP, "%s: LayerDown.\n", fp->name); 250 StopTimer(&IpcpReportTimer); 251 } 252 253 /* 254 * Called when IPCP has reached to OPEN state 255 */ 256 static void 257 IpcpLayerUp(fp) 258 struct fsm *fp; 259 { 260 char tbuff[100]; 261 262 #ifdef VERBOSE 263 fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state); 264 #endif 265 Prompt(1); 266 LogPrintf(LOG_LCP, "%s: LayerUp.\n", fp->name); 267 sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr)); 268 LogPrintf(LOG_LCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); 269 OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask); 270 OsLinkup(); 271 IpcpStartReport(); 272 StartIdleTimer(); 273 } 274 275 void 276 IpcpUp() 277 { 278 FsmUp(&IpcpFsm); 279 LogPrintf(LOG_LCP, "IPCP Up event!!\n"); 280 } 281 282 void 283 IpcpOpen() 284 { 285 FsmOpen(&IpcpFsm); 286 } 287 288 static int 289 AcceptableAddr(prange, ipaddr) 290 struct in_range *prange; 291 struct in_addr ipaddr; 292 { 293 #ifdef DEBUG 294 logprintf("requested = %x ", htonl(ipaddr.s_addr)); 295 logprintf("range = %x", htonl(prange->ipaddr.s_addr)); 296 logprintf("/%x\n", htonl(prange->mask.s_addr)); 297 logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr), 298 htonl(ipaddr.s_addr & prange->mask.s_addr)); 299 #endif 300 return((prange->ipaddr.s_addr & prange->mask.s_addr) == 301 (ipaddr.s_addr & prange->mask.s_addr)); 302 } 303 304 static void 305 IpcpDecodeConfig(cp, plen, mode) 306 u_char *cp; 307 int plen; 308 int mode; 309 { 310 int type, length; 311 u_long *lp, compproto; 312 struct compreq *pcomp; 313 struct in_addr ipaddr, dstipaddr; 314 char tbuff[100]; 315 316 ackp = AckBuff; 317 nakp = NakBuff; 318 rejp = RejBuff; 319 320 while (plen >= sizeof(struct fsmconfig)) { 321 if (plen < 0) 322 break; 323 type = *cp; 324 length = cp[1]; 325 if (type <= TY_IPADDR) 326 sprintf(tbuff, " %s[%d] ", cftypes[type], length); 327 else 328 sprintf(tbuff, " "); 329 330 switch (type) { 331 case TY_IPADDR: /* RFC1332 */ 332 lp = (u_long *)(cp + 2); 333 ipaddr.s_addr = *lp; 334 LogPrintf(LOG_LCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 335 336 switch (mode) { 337 case MODE_REQ: 338 if (!AcceptableAddr(&DefHisAddress, ipaddr)) { 339 /* 340 * If destination address is not acceptable, insist to use 341 * what we want to use. 342 */ 343 bcopy(cp, nakp, 2); 344 bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length); 345 nakp += length; 346 break; 347 348 } 349 IpcpInfo.his_ipaddr = ipaddr; 350 bcopy(cp, ackp, length); 351 ackp += length; 352 break; 353 case MODE_NAK: 354 if (AcceptableAddr(&DefMyAddress, ipaddr)) { 355 /* 356 * Use address suggested by peer. 357 */ 358 sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 359 LogPrintf(LOG_LCP, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr)); 360 IpcpInfo.want_ipaddr = ipaddr; 361 } 362 break; 363 case MODE_REJ: 364 IpcpInfo.his_reject |= (1 << type); 365 break; 366 } 367 break; 368 case TY_COMPPROTO: 369 lp = (u_long *)(cp + 2); 370 compproto = htonl(*lp); 371 LogPrintf(LOG_LCP, "%s %08x\n", tbuff, compproto); 372 373 switch (mode) { 374 case MODE_REQ: 375 if (!Acceptable(ConfVjcomp)) { 376 bcopy(cp, rejp, length); 377 rejp += length; 378 } else { 379 pcomp = (struct compreq *)(cp + 2); 380 switch (length) { 381 case 4: /* RFC1172 */ 382 if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 383 logprintf("** Peer is speaking RFC1172 compression protocol **\n"); 384 IpcpInfo.heis1172 = 1; 385 IpcpInfo.his_compproto = compproto; 386 bcopy(cp, ackp, length); 387 ackp += length; 388 } else { 389 bcopy(cp, nakp, 2); 390 pcomp->proto = htons(PROTO_VJCOMP); 391 bcopy(&pcomp, nakp + 2, 2); 392 nakp += length; 393 } 394 break; 395 case 6: /* RFC1332 */ 396 if (ntohs(pcomp->proto) == PROTO_VJCOMP 397 && pcomp->slots < MAX_STATES && pcomp->slots > 2) { 398 IpcpInfo.his_compproto = compproto; 399 IpcpInfo.heis1172 = 0; 400 bcopy(cp, ackp, length); 401 ackp += length; 402 } else { 403 bcopy(cp, nakp, 2); 404 pcomp->proto = htons(PROTO_VJCOMP); 405 pcomp->slots = MAX_STATES - 1; 406 pcomp->compcid = 0; 407 bcopy(&pcomp, nakp + 2, sizeof(pcomp)); 408 nakp += length; 409 } 410 break; 411 default: 412 bcopy(cp, rejp, length); 413 rejp += length; 414 break; 415 } 416 } 417 break; 418 case MODE_NAK: 419 LogPrintf(LOG_LCP, "%s changing compproto: %08x --> %08x\n", 420 tbuff, IpcpInfo.want_compproto, compproto); 421 IpcpInfo.want_compproto = compproto; 422 break; 423 case MODE_REJ: 424 IpcpInfo.his_reject |= (1 << type); 425 break; 426 } 427 break; 428 case TY_IPADDRS: /* RFC1172 */ 429 lp = (u_long *)(cp + 2); 430 ipaddr.s_addr = *lp; 431 lp = (u_long *)(cp + 6); 432 dstipaddr.s_addr = *lp; 433 LogPrintf(LOG_LCP, "%s %s, ", tbuff, inet_ntoa(ipaddr)); 434 LogPrintf(LOG_LCP, "%s\n", inet_ntoa(dstipaddr)); 435 436 switch (mode) { 437 case MODE_REQ: 438 IpcpInfo.his_ipaddr = ipaddr; 439 IpcpInfo.want_ipaddr = dstipaddr; 440 bcopy(cp, ackp, length); 441 ackp += length; 442 break; 443 case MODE_NAK: 444 LogPrintf(LOG_LCP, "%s changing address: %s ", 445 tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 446 LogPrintf(LOG_LCP, "--> %s\n", inet_ntoa(ipaddr)); 447 IpcpInfo.want_ipaddr = ipaddr; 448 IpcpInfo.his_ipaddr = dstipaddr; 449 break; 450 case MODE_REJ: 451 IpcpInfo.his_reject |= (1 << type); 452 break; 453 } 454 break; 455 default: 456 IpcpInfo.my_reject |= (1 << type); 457 bcopy(cp, rejp, length); 458 rejp += length; 459 break; 460 } 461 plen -= length; 462 cp += length; 463 } 464 } 465 466 void 467 IpcpInput(struct mbuf *bp) 468 { 469 FsmInput(&IpcpFsm, bp); 470 } 471