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.9 1996/10/06 13:32:28 jkh 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 #include "alias.h" 39 40 extern void PutConfValue(); 41 extern void Prompt(); 42 extern struct in_addr ifnetmask; 43 44 struct ipcpstate IpcpInfo; 45 struct in_range DefMyAddress, DefHisAddress, DefTriggerAddress; 46 47 #ifdef MSEXT 48 struct in_addr ns_entries[2], nbns_entries[2]; 49 #endif /* MSEXT */ 50 51 static void IpcpSendConfigReq __P((struct fsm *)); 52 static void IpcpSendTerminateAck __P((struct fsm *)); 53 static void IpcpSendTerminateReq __P((struct fsm *)); 54 static void IpcpDecodeConfig __P((u_char *, int, int)); 55 static void IpcpLayerStart __P((struct fsm *)); 56 static void IpcpLayerFinish __P((struct fsm *)); 57 static void IpcpLayerUp __P((struct fsm *)); 58 static void IpcpLayerDown __P((struct fsm *)); 59 static void IpcpInitRestartCounter __P((struct fsm *)); 60 61 struct pppTimer IpcpReportTimer; 62 63 static int lastInOctets, lastOutOctets; 64 65 #define REJECTED(p, x) (p->his_reject & (1<<x)) 66 67 struct fsm IpcpFsm = { 68 "IPCP", 69 PROTO_IPCP, 70 IPCP_MAXCODE, 71 OPEN_ACTIVE, 72 ST_INITIAL, 73 0, 0, 0, 74 75 0, 76 { 0, 0, 0, NULL, NULL, NULL }, 77 78 IpcpLayerUp, 79 IpcpLayerDown, 80 IpcpLayerStart, 81 IpcpLayerFinish, 82 IpcpInitRestartCounter, 83 IpcpSendConfigReq, 84 IpcpSendTerminateReq, 85 IpcpSendTerminateAck, 86 IpcpDecodeConfig, 87 }; 88 89 static char *cftypes[] = { 90 "???", "IPADDRS", "COMPPROTO", "IPADDR", 91 }; 92 93 /* 94 * Function called every second. Updates connection period and idle period, 95 * also update LQR information. 96 */ 97 static void 98 IpcpReportFunc() 99 { 100 ipConnectSecs++; 101 if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets) 102 ipIdleSecs++; 103 lastInOctets = ipInOctets; 104 lastOutOctets = ipOutOctets; 105 StopTimer(&IpcpReportTimer); 106 IpcpReportTimer.state = TIMER_STOPPED; 107 StartTimer(&IpcpReportTimer); 108 } 109 110 static void 111 IpcpStartReport() 112 { 113 ipIdleSecs = ipConnectSecs = 0; 114 StopTimer(&IpcpReportTimer); 115 IpcpReportTimer.state = TIMER_STOPPED; 116 IpcpReportTimer.load = SECTICKS; 117 IpcpReportTimer.func = IpcpReportFunc; 118 StartTimer(&IpcpReportTimer); 119 } 120 121 void 122 ReportIpcpStatus() 123 { 124 struct ipcpstate *icp = &IpcpInfo; 125 struct fsm *fp = &IpcpFsm; 126 127 printf("%s [%s]\n", fp->name, StateNames[fp->state]); 128 printf(" his side: %s, %lx\n", 129 inet_ntoa(icp->his_ipaddr), icp->his_compproto); 130 printf(" my side: %s, %lx\n", 131 inet_ntoa(icp->want_ipaddr), icp->want_compproto); 132 printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs); 133 printf("Defaults:\n"); 134 printf(" My Address: %s/%d\n", 135 inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width); 136 printf(" His Address: %s/%d\n", 137 inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width); 138 printf(" Negotiation: %s/%d\n", 139 inet_ntoa(DefTriggerAddress.ipaddr), DefTriggerAddress.width); 140 } 141 142 void 143 IpcpDefAddress() 144 { 145 struct hostent *hp; 146 char name[200]; 147 148 bzero(&DefMyAddress, sizeof(DefMyAddress)); 149 bzero(&DefHisAddress, sizeof(DefHisAddress)); 150 bzero(&DefTriggerAddress, sizeof(DefTriggerAddress)); 151 if (gethostname(name, sizeof(name)) == 0) { 152 hp = gethostbyname(name); 153 if (hp && hp->h_addrtype == AF_INET) { 154 bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length); 155 } 156 } 157 } 158 159 void 160 IpcpInit() 161 { 162 struct ipcpstate *icp = &IpcpInfo; 163 164 FsmInit(&IpcpFsm); 165 bzero(icp, sizeof(struct ipcpstate)); 166 if ((mode & MODE_DEDICATED) && !dstsystem) { 167 icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0; 168 } else { 169 icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; 170 icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; 171 } 172 173 /* 174 * Some implementation of PPP are: 175 * Starting a negotiaion by require sending *special* value as my address, 176 * even though standard of PPP is defined full negotiation based. 177 * (e.g. "0.0.0.0" or Not "0.0.0.0") 178 */ 179 if ( icp->want_ipaddr.s_addr == 0 ) { 180 icp->want_ipaddr.s_addr = DefTriggerAddress.ipaddr.s_addr; 181 } 182 183 if (Enabled(ConfVjcomp)) 184 icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8); 185 else 186 icp->want_compproto = 0; 187 icp->heis1172 = 0; 188 IpcpFsm.maxconfig = 10; 189 } 190 191 static void 192 IpcpInitRestartCounter(fp) 193 struct fsm *fp; 194 { 195 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 196 fp->restart = 5; 197 } 198 199 static void 200 IpcpSendConfigReq(fp) 201 struct fsm *fp; 202 { 203 u_char *cp; 204 struct ipcpstate *icp = &IpcpInfo; 205 206 cp = ReqBuff; 207 LogPrintf(LOG_LCP_BIT, "%s: SendConfigReq\n", fp->name); 208 if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR)) 209 PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr)); 210 if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) { 211 if (icp->heis1172) 212 PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16); 213 else 214 PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto); 215 } 216 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 217 } 218 219 static void 220 IpcpSendTerminateReq(fp) 221 struct fsm *fp; 222 { 223 /* XXX: No code yet */ 224 } 225 226 static void 227 IpcpSendTerminateAck(fp) 228 struct fsm *fp; 229 { 230 LogPrintf(LOG_LCP_BIT, " %s: SendTerminateAck\n", fp->name); 231 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 232 } 233 234 static void 235 IpcpLayerStart(fp) 236 struct fsm *fp; 237 { 238 LogPrintf(LOG_LCP_BIT, "%s: LayerStart.\n", fp->name); 239 } 240 241 static void 242 IpcpLayerFinish(fp) 243 struct fsm *fp; 244 { 245 LogPrintf(LOG_LCP_BIT, "%s: LayerFinish.\n", fp->name); 246 LcpClose(); 247 NewPhase(PHASE_TERMINATE); 248 } 249 250 static void 251 IpcpLayerDown(fp) 252 struct fsm *fp; 253 { 254 LogPrintf(LOG_LCP_BIT, "%s: LayerDown.\n", fp->name); 255 StopTimer(&IpcpReportTimer); 256 } 257 258 /* 259 * Called when IPCP has reached to OPEN state 260 */ 261 static void 262 IpcpLayerUp(fp) 263 struct fsm *fp; 264 { 265 char tbuff[100]; 266 267 #ifdef VERBOSE 268 fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state); 269 #endif 270 Prompt(1); 271 LogPrintf(LOG_LCP_BIT, "%s: LayerUp.\n", fp->name); 272 sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr)); 273 LogPrintf(LOG_LCP_BIT|LOG_LINK_BIT, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); 274 OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask); 275 OsLinkup(); 276 IpcpStartReport(); 277 StartIdleTimer(); 278 if (mode & MODE_ALIAS) 279 SetAliasAddress(IpcpInfo.want_ipaddr); 280 } 281 282 void 283 IpcpUp() 284 { 285 FsmUp(&IpcpFsm); 286 LogPrintf(LOG_LCP_BIT, "IPCP Up event!!\n"); 287 } 288 289 void 290 IpcpOpen() 291 { 292 FsmOpen(&IpcpFsm); 293 } 294 295 static int 296 AcceptableAddr(prange, ipaddr) 297 struct in_range *prange; 298 struct in_addr ipaddr; 299 { 300 #ifdef DEBUG 301 logprintf("requested = %x ", htonl(ipaddr.s_addr)); 302 logprintf("range = %x", htonl(prange->ipaddr.s_addr)); 303 logprintf("/%x\n", htonl(prange->mask.s_addr)); 304 logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr), 305 htonl(ipaddr.s_addr & prange->mask.s_addr)); 306 #endif 307 return((prange->ipaddr.s_addr & prange->mask.s_addr) == 308 (ipaddr.s_addr & prange->mask.s_addr)); 309 } 310 311 static void 312 IpcpDecodeConfig(cp, plen, mode) 313 u_char *cp; 314 int plen; 315 int mode; 316 { 317 int type, length; 318 u_long *lp, compproto; 319 struct compreq *pcomp; 320 struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req; 321 char tbuff[100]; 322 323 ackp = AckBuff; 324 nakp = NakBuff; 325 rejp = RejBuff; 326 327 while (plen >= sizeof(struct fsmconfig)) { 328 if (plen < 0) 329 break; 330 type = *cp; 331 length = cp[1]; 332 if (type <= TY_IPADDR) 333 sprintf(tbuff, " %s[%d] ", cftypes[type], length); 334 else 335 sprintf(tbuff, " "); 336 337 switch (type) { 338 case TY_IPADDR: /* RFC1332 */ 339 lp = (u_long *)(cp + 2); 340 ipaddr.s_addr = *lp; 341 LogPrintf(LOG_LCP_BIT, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 342 343 switch (mode) { 344 case MODE_REQ: 345 if (!AcceptableAddr(&DefHisAddress, ipaddr)) { 346 /* 347 * If destination address is not acceptable, insist to use 348 * what we want to use. 349 */ 350 bcopy(cp, nakp, 2); 351 bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length); 352 nakp += length; 353 break; 354 355 } 356 IpcpInfo.his_ipaddr = ipaddr; 357 bcopy(cp, ackp, length); 358 ackp += length; 359 break; 360 case MODE_NAK: 361 if (AcceptableAddr(&DefMyAddress, ipaddr)) { 362 /* 363 * Use address suggested by peer. 364 */ 365 sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 366 LogPrintf(LOG_LCP_BIT, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr)); 367 IpcpInfo.want_ipaddr = ipaddr; 368 } 369 break; 370 case MODE_REJ: 371 IpcpInfo.his_reject |= (1 << type); 372 break; 373 } 374 break; 375 case TY_COMPPROTO: 376 lp = (u_long *)(cp + 2); 377 compproto = htonl(*lp); 378 LogPrintf(LOG_LCP_BIT, "%s %08x\n", tbuff, compproto); 379 380 switch (mode) { 381 case MODE_REQ: 382 if (!Acceptable(ConfVjcomp)) { 383 bcopy(cp, rejp, length); 384 rejp += length; 385 } else { 386 pcomp = (struct compreq *)(cp + 2); 387 switch (length) { 388 case 4: /* RFC1172 */ 389 if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 390 logprintf("** Peer is speaking RFC1172 compression protocol **\n"); 391 IpcpInfo.heis1172 = 1; 392 IpcpInfo.his_compproto = compproto; 393 bcopy(cp, ackp, length); 394 ackp += length; 395 } else { 396 bcopy(cp, nakp, 2); 397 pcomp->proto = htons(PROTO_VJCOMP); 398 bcopy(&pcomp, nakp + 2, 2); 399 nakp += length; 400 } 401 break; 402 case 6: /* RFC1332 */ 403 if (ntohs(pcomp->proto) == PROTO_VJCOMP 404 && pcomp->slots < MAX_STATES && pcomp->slots > 2) { 405 IpcpInfo.his_compproto = compproto; 406 IpcpInfo.heis1172 = 0; 407 bcopy(cp, ackp, length); 408 ackp += length; 409 } else { 410 bcopy(cp, nakp, 2); 411 pcomp->proto = htons(PROTO_VJCOMP); 412 pcomp->slots = MAX_STATES - 1; 413 pcomp->compcid = 0; 414 bcopy(&pcomp, nakp + 2, sizeof(pcomp)); 415 nakp += length; 416 } 417 break; 418 default: 419 bcopy(cp, rejp, length); 420 rejp += length; 421 break; 422 } 423 } 424 break; 425 case MODE_NAK: 426 LogPrintf(LOG_LCP_BIT, "%s changing compproto: %08x --> %08x\n", 427 tbuff, IpcpInfo.want_compproto, compproto); 428 IpcpInfo.want_compproto = compproto; 429 break; 430 case MODE_REJ: 431 IpcpInfo.his_reject |= (1 << type); 432 break; 433 } 434 break; 435 case TY_IPADDRS: /* RFC1172 */ 436 lp = (u_long *)(cp + 2); 437 ipaddr.s_addr = *lp; 438 lp = (u_long *)(cp + 6); 439 dstipaddr.s_addr = *lp; 440 LogPrintf(LOG_LCP_BIT, "%s %s, ", tbuff, inet_ntoa(ipaddr)); 441 LogPrintf(LOG_LCP_BIT, "%s\n", inet_ntoa(dstipaddr)); 442 443 switch (mode) { 444 case MODE_REQ: 445 IpcpInfo.his_ipaddr = ipaddr; 446 IpcpInfo.want_ipaddr = dstipaddr; 447 bcopy(cp, ackp, length); 448 ackp += length; 449 break; 450 case MODE_NAK: 451 LogPrintf(LOG_LCP_BIT, "%s changing address: %s ", 452 tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 453 LogPrintf(LOG_LCP_BIT, "--> %s\n", inet_ntoa(ipaddr)); 454 IpcpInfo.want_ipaddr = ipaddr; 455 IpcpInfo.his_ipaddr = dstipaddr; 456 break; 457 case MODE_REJ: 458 IpcpInfo.his_reject |= (1 << type); 459 break; 460 } 461 break; 462 463 /* 464 * MS extensions for MS's PPP 465 */ 466 467 #ifdef MSEXT 468 case TY_PRIMARY_DNS: /* MS PPP DNS negotiation hack */ 469 case TY_SECONDARY_DNS: 470 if( !Enabled( ConfMSExt ) ) { 471 LogPrintf( LOG_LCP, "MS NS req - rejected - msext disabled\n" ); 472 IpcpInfo.my_reject |= ( 1 << type ); 473 bcopy(cp, rejp, length); 474 rejp += length; 475 break; 476 } 477 switch( mode ){ 478 case MODE_REQ: 479 lp = (u_long *)(cp + 2); 480 dnsstuff.s_addr = *lp; 481 ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS)?1:0)].s_addr; 482 if( dnsstuff.s_addr != ms_info_req.s_addr ) 483 { 484 /* 485 So the client has got the DNS stuff wrong (first request) 486 so well tell 'em how it is 487 */ 488 bcopy( cp, nakp, 2 ); /* copy first two (type/length) */ 489 LogPrintf( LOG_LCP, "MS NS req %d:%s->%s - nak\n", 490 type, 491 inet_ntoa( dnsstuff ), 492 inet_ntoa( ms_info_req )); 493 bcopy( &ms_info_req, nakp+2, length ); 494 nakp += length; 495 break; 496 } 497 /* 498 Otherwise they have it right (this time) so we send 499 a ack packet back confirming it... end of story 500 */ 501 LogPrintf( LOG_LCP, "MS NS req %d:%s ok - ack\n", 502 type, 503 inet_ntoa( ms_info_req )); 504 bcopy( cp, ackp, length ); 505 ackp += length; 506 break; 507 case MODE_NAK: /* what does this mean?? */ 508 LogPrintf(LOG_LCP, "MS NS req %d - NAK??\n", type ); 509 break; 510 case MODE_REJ: /* confused?? me to :) */ 511 LogPrintf(LOG_LCP, "MS NS req %d - REJ??\n", type ); 512 break; 513 } 514 break; 515 516 case TY_PRIMARY_NBNS: /* MS PPP NetBIOS nameserver hack */ 517 case TY_SECONDARY_NBNS: 518 if( !Enabled( ConfMSExt ) ) { 519 LogPrintf( LOG_LCP, "MS NBNS req - rejected - msext disabled\n" ); 520 IpcpInfo.my_reject |= ( 1 << type ); 521 bcopy( cp, rejp, length ); 522 rejp += length; 523 break; 524 } 525 switch( mode ){ 526 case MODE_REQ: 527 lp = (u_long *)(cp + 2); 528 dnsstuff.s_addr = *lp; 529 ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS)?1:0)].s_addr; 530 if( dnsstuff.s_addr != ms_info_req.s_addr ) 531 { 532 bcopy( cp, nakp, 2 ); 533 bcopy( &ms_info_req.s_addr , nakp+2, length ); 534 LogPrintf( LOG_LCP, "MS NBNS req %d:%s->%s - nak\n", 535 type, 536 inet_ntoa( dnsstuff ), 537 inet_ntoa( ms_info_req )); 538 nakp += length; 539 break; 540 } 541 LogPrintf( LOG_LCP, "MS NBNS req %d:%s ok - ack\n", 542 type, 543 inet_ntoa( ms_info_req )); 544 bcopy( cp, ackp, length ); 545 ackp += length; 546 break; 547 case MODE_NAK: 548 LogPrintf( LOG_LCP, "MS NBNS req %d - NAK??\n", type ); 549 break; 550 case MODE_REJ: 551 LogPrintf( LOG_LCP, "MS NBNS req %d - REJ??\n", type ); 552 break; 553 } 554 break; 555 556 #endif /* MSEXT */ 557 558 default: 559 IpcpInfo.my_reject |= (1 << type); 560 bcopy(cp, rejp, length); 561 rejp += length; 562 break; 563 } 564 plen -= length; 565 cp += length; 566 } 567 } 568 569 void 570 IpcpInput(struct mbuf *bp) 571 { 572 FsmInput(&IpcpFsm, bp); 573 } 574