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