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