ipcp.c revision 26098
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.18 1997/05/23 04:54:02 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 <alias.h> 35#include "slcompress.h" 36#include "os.h" 37#include "phase.h" 38#include "vars.h" 39 40extern void PutConfValue(); 41extern void Prompt(); 42extern struct in_addr ifnetmask; 43 44struct ipcpstate IpcpInfo; 45struct in_range DefMyAddress, DefHisAddress, DefTriggerAddress; 46 47#ifdef MSEXT 48struct in_addr ns_entries[2], nbns_entries[2]; 49#endif /* MSEXT */ 50 51static void IpcpSendConfigReq __P((struct fsm *)); 52static void IpcpSendTerminateAck __P((struct fsm *)); 53static void IpcpSendTerminateReq __P((struct fsm *)); 54static void IpcpDecodeConfig __P((u_char *, int, int)); 55static void IpcpLayerStart __P((struct fsm *)); 56static void IpcpLayerFinish __P((struct fsm *)); 57static void IpcpLayerUp __P((struct fsm *)); 58static void IpcpLayerDown __P((struct fsm *)); 59static void IpcpInitRestartCounter __P((struct fsm *)); 60 61struct pppTimer IpcpReportTimer; 62 63static int lastInOctets, lastOutOctets; 64 65#define REJECTED(p, x) (p->his_reject & (1<<x)) 66 67struct 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 89static 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 */ 97static void 98IpcpReportFunc() 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 110static void 111IpcpStartReport() 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 121int 122ReportIpcpStatus() 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 return 1; 141} 142 143void 144IpcpDefAddress() 145{ 146 struct hostent *hp; 147 char name[200]; 148 149 bzero(&DefMyAddress, sizeof(DefMyAddress)); 150 bzero(&DefHisAddress, sizeof(DefHisAddress)); 151 bzero(&DefTriggerAddress, sizeof(DefTriggerAddress)); 152 if (gethostname(name, sizeof(name)) == 0) { 153 hp = gethostbyname(name); 154 if (hp && hp->h_addrtype == AF_INET) { 155 bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length); 156 } 157 } 158} 159 160void 161IpcpInit() 162{ 163 struct ipcpstate *icp = &IpcpInfo; 164 165 FsmInit(&IpcpFsm); 166 bzero(icp, sizeof(struct ipcpstate)); 167 if ((mode & MODE_DEDICATED) && !dstsystem) { 168 icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0; 169 } else { 170 icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; 171 icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; 172 } 173 174 /* 175 * Some implementation of PPP are: 176 * Starting a negotiaion by require sending *special* value as my address, 177 * even though standard of PPP is defined full negotiation based. 178 * (e.g. "0.0.0.0" or Not "0.0.0.0") 179 */ 180 if ( icp->want_ipaddr.s_addr == 0 ) { 181 icp->want_ipaddr.s_addr = DefTriggerAddress.ipaddr.s_addr; 182 } 183 184 if (Enabled(ConfVjcomp)) 185 icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8); 186 else 187 icp->want_compproto = 0; 188 icp->heis1172 = 0; 189 IpcpFsm.maxconfig = 10; 190} 191 192static void 193IpcpInitRestartCounter(fp) 194struct fsm *fp; 195{ 196 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 197 fp->restart = 5; 198} 199 200static void 201IpcpSendConfigReq(fp) 202struct fsm *fp; 203{ 204 u_char *cp; 205 struct ipcpstate *icp = &IpcpInfo; 206 207 cp = ReqBuff; 208 LogPrintf(LOG_LCP_BIT, "%s: SendConfigReq\n", fp->name); 209 if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR)) 210 PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr)); 211 if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) { 212 if (icp->heis1172) 213 PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16); 214 else 215 PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto); 216 } 217 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 218} 219 220static void 221IpcpSendTerminateReq(fp) 222struct fsm *fp; 223{ 224 /* XXX: No code yet */ 225} 226 227static void 228IpcpSendTerminateAck(fp) 229struct fsm *fp; 230{ 231 LogPrintf(LOG_LCP_BIT, " %s: SendTerminateAck\n", fp->name); 232 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 233} 234 235static void 236IpcpLayerStart(fp) 237struct fsm *fp; 238{ 239 LogPrintf(LOG_LCP_BIT, "%s: LayerStart.\n", fp->name); 240} 241 242static void 243IpcpLayerFinish(fp) 244struct fsm *fp; 245{ 246 LogPrintf(LOG_LCP_BIT, "%s: LayerFinish.\n", fp->name); 247 reconnect(RECON_FALSE); 248 LcpClose(); 249 NewPhase(PHASE_TERMINATE); 250} 251 252static void 253IpcpLayerDown(fp) 254struct fsm *fp; 255{ 256 LogPrintf(LOG_LCP_BIT, "%s: LayerDown.\n", fp->name); 257 StopTimer(&IpcpReportTimer); 258} 259 260/* 261 * Called when IPCP has reached to OPEN state 262 */ 263static void 264IpcpLayerUp(fp) 265struct fsm *fp; 266{ 267 char tbuff[100]; 268 269#ifdef VERBOSE 270 fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state); 271#endif 272 Prompt(); 273 LogPrintf(LOG_LCP_BIT, "%s: LayerUp.\n", fp->name); 274 snprintf(tbuff, sizeof(tbuff), "myaddr = %s ", 275 inet_ntoa(IpcpInfo.want_ipaddr)); 276 LogPrintf(LOG_LCP_BIT|LOG_LINK_BIT, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); 277 if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask) < 0) { 278 printf("unable to set ip address\n"); 279 return; 280 } 281 OsLinkup(); 282 IpcpStartReport(); 283 StartIdleTimer(); 284 if (mode & MODE_ALIAS) 285 SetPacketAliasAddress(IpcpInfo.want_ipaddr); 286} 287 288void 289IpcpUp() 290{ 291 FsmUp(&IpcpFsm); 292 LogPrintf(LOG_LCP_BIT, "IPCP Up event!!\n"); 293} 294 295void 296IpcpOpen() 297{ 298 FsmOpen(&IpcpFsm); 299} 300 301static int 302AcceptableAddr(prange, ipaddr) 303struct in_range *prange; 304struct in_addr ipaddr; 305{ 306#ifdef DEBUG 307 logprintf("requested = %x ", htonl(ipaddr.s_addr)); 308 logprintf("range = %x", htonl(prange->ipaddr.s_addr)); 309 logprintf("/%x\n", htonl(prange->mask.s_addr)); 310 logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr), 311 htonl(ipaddr.s_addr & prange->mask.s_addr)); 312#endif 313 return (prange->ipaddr.s_addr & prange->mask.s_addr) == 314 (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; 315} 316 317static void 318IpcpDecodeConfig(cp, plen, mode) 319u_char *cp; 320int plen; 321int 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(LOG_LCP_BIT, "%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(LOG_LCP_BIT, "%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(LOG_LCP_BIT, "%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("** 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(LOG_LCP_BIT, "%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(LOG_LCP_BIT, "%s %s, ", tbuff, inet_ntoa(ipaddr)); 448 LogPrintf(LOG_LCP_BIT, "%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(LOG_LCP_BIT, "%s changing address: %s ", 459 tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 460 LogPrintf(LOG_LCP_BIT, "--> %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#ifdef MSEXT 475 case TY_PRIMARY_DNS: /* MS PPP DNS negotiation hack */ 476 case TY_SECONDARY_DNS: 477 if( !Enabled( ConfMSExt ) ) { 478 LogPrintf( LOG_LCP, "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( LOG_LCP, "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( LOG_LCP, "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(LOG_LCP, "MS NS req %d - NAK??\n", type ); 516 break; 517 case MODE_REJ: /* confused?? me to :) */ 518 LogPrintf(LOG_LCP, "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( LOG_LCP, "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( LOG_LCP, "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( LOG_LCP, "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( LOG_LCP, "MS NBNS req %d - NAK??\n", type ); 556 break; 557 case MODE_REJ: 558 LogPrintf( LOG_LCP, "MS NBNS req %d - REJ??\n", type ); 559 break; 560 } 561 break; 562 563#endif /* MSEXT */ 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 576void 577IpcpInput(struct mbuf *bp) 578{ 579 FsmInput(&IpcpFsm, bp); 580} 581