ipcp.c revision 25630
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.13 1997/02/22 16:10:20 peter 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 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 0; 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 LcpClose(); 248 NewPhase(PHASE_TERMINATE); 249} 250 251static void 252IpcpLayerDown(fp) 253struct fsm *fp; 254{ 255 LogPrintf(LOG_LCP_BIT, "%s: LayerDown.\n", fp->name); 256 StopTimer(&IpcpReportTimer); 257} 258 259/* 260 * Called when IPCP has reached to OPEN state 261 */ 262static void 263IpcpLayerUp(fp) 264struct fsm *fp; 265{ 266 char tbuff[100]; 267 268#ifdef VERBOSE 269 fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state); 270#endif 271 Prompt(); 272 LogPrintf(LOG_LCP_BIT, "%s: LayerUp.\n", fp->name); 273 snprintf(tbuff, sizeof(tbuff), "myaddr = %s ", 274 inet_ntoa(IpcpInfo.want_ipaddr)); 275 LogPrintf(LOG_LCP_BIT|LOG_LINK_BIT, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); 276 if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask) < 0) { 277 printf("unable to set ip address\n"); 278 return; 279 } 280 OsLinkup(); 281 IpcpStartReport(); 282 StartIdleTimer(); 283 if (mode & MODE_ALIAS) 284 SetAliasAddress(IpcpInfo.want_ipaddr); 285} 286 287void 288IpcpUp() 289{ 290 FsmUp(&IpcpFsm); 291 LogPrintf(LOG_LCP_BIT, "IPCP Up event!!\n"); 292} 293 294void 295IpcpOpen() 296{ 297 FsmOpen(&IpcpFsm); 298} 299 300static int 301AcceptableAddr(prange, ipaddr) 302struct in_range *prange; 303struct in_addr ipaddr; 304{ 305#ifdef DEBUG 306 logprintf("requested = %x ", htonl(ipaddr.s_addr)); 307 logprintf("range = %x", htonl(prange->ipaddr.s_addr)); 308 logprintf("/%x\n", htonl(prange->mask.s_addr)); 309 logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr), 310 htonl(ipaddr.s_addr & prange->mask.s_addr)); 311#endif 312 return((prange->ipaddr.s_addr & prange->mask.s_addr) == 313 (ipaddr.s_addr & prange->mask.s_addr)); 314} 315 316static void 317IpcpDecodeConfig(cp, plen, mode) 318u_char *cp; 319int plen; 320int mode; 321{ 322 int type, length; 323 u_long *lp, compproto; 324 struct compreq *pcomp; 325 struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req; 326 char tbuff[100]; 327 char tbuff2[100]; 328 329 ackp = AckBuff; 330 nakp = NakBuff; 331 rejp = RejBuff; 332 333 while (plen >= sizeof(struct fsmconfig)) { 334 if (plen < 0) 335 break; 336 type = *cp; 337 length = cp[1]; 338 if (type <= TY_IPADDR) 339 snprintf(tbuff, sizeof(tbuff), " %s[%d] ", cftypes[type], length); 340 else 341 snprintf(tbuff, sizeof(tbuff), " "); 342 343 switch (type) { 344 case TY_IPADDR: /* RFC1332 */ 345 lp = (u_long *)(cp + 2); 346 ipaddr.s_addr = *lp; 347 LogPrintf(LOG_LCP_BIT, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 348 349 switch (mode) { 350 case MODE_REQ: 351 if (!AcceptableAddr(&DefHisAddress, ipaddr)) { 352 /* 353 * If destination address is not acceptable, insist to use 354 * what we want to use. 355 */ 356 bcopy(cp, nakp, 2); 357 bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length); 358 nakp += length; 359 break; 360 361 } 362 IpcpInfo.his_ipaddr = ipaddr; 363 bcopy(cp, ackp, length); 364 ackp += length; 365 break; 366 case MODE_NAK: 367 if (AcceptableAddr(&DefMyAddress, ipaddr)) { 368 /* 369 * Use address suggested by peer. 370 */ 371 snprintf(tbuff2, sizeof(tbuff2), "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 372 LogPrintf(LOG_LCP_BIT, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); 373 IpcpInfo.want_ipaddr = ipaddr; 374 } 375 break; 376 case MODE_REJ: 377 IpcpInfo.his_reject |= (1 << type); 378 break; 379 } 380 break; 381 case TY_COMPPROTO: 382 lp = (u_long *)(cp + 2); 383 compproto = htonl(*lp); 384 LogPrintf(LOG_LCP_BIT, "%s %08x\n", tbuff, compproto); 385 386 switch (mode) { 387 case MODE_REQ: 388 if (!Acceptable(ConfVjcomp)) { 389 bcopy(cp, rejp, length); 390 rejp += length; 391 } else { 392 pcomp = (struct compreq *)(cp + 2); 393 switch (length) { 394 case 4: /* RFC1172 */ 395 if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 396 logprintf("** Peer is speaking RFC1172 compression protocol **\n"); 397 IpcpInfo.heis1172 = 1; 398 IpcpInfo.his_compproto = compproto; 399 bcopy(cp, ackp, length); 400 ackp += length; 401 } else { 402 bcopy(cp, nakp, 2); 403 pcomp->proto = htons(PROTO_VJCOMP); 404 bcopy(&pcomp, nakp + 2, 2); 405 nakp += length; 406 } 407 break; 408 case 6: /* RFC1332 */ 409 if (ntohs(pcomp->proto) == PROTO_VJCOMP 410 && pcomp->slots < MAX_STATES && pcomp->slots > 2) { 411 IpcpInfo.his_compproto = compproto; 412 IpcpInfo.heis1172 = 0; 413 bcopy(cp, ackp, length); 414 ackp += length; 415 } else { 416 bcopy(cp, nakp, 2); 417 pcomp->proto = htons(PROTO_VJCOMP); 418 pcomp->slots = MAX_STATES - 1; 419 pcomp->compcid = 0; 420 bcopy(&pcomp, nakp + 2, sizeof(pcomp)); 421 nakp += length; 422 } 423 break; 424 default: 425 bcopy(cp, rejp, length); 426 rejp += length; 427 break; 428 } 429 } 430 break; 431 case MODE_NAK: 432 LogPrintf(LOG_LCP_BIT, "%s changing compproto: %08x --> %08x\n", 433 tbuff, IpcpInfo.want_compproto, compproto); 434 IpcpInfo.want_compproto = compproto; 435 break; 436 case MODE_REJ: 437 IpcpInfo.his_reject |= (1 << type); 438 break; 439 } 440 break; 441 case TY_IPADDRS: /* RFC1172 */ 442 lp = (u_long *)(cp + 2); 443 ipaddr.s_addr = *lp; 444 lp = (u_long *)(cp + 6); 445 dstipaddr.s_addr = *lp; 446 LogPrintf(LOG_LCP_BIT, "%s %s, ", tbuff, inet_ntoa(ipaddr)); 447 LogPrintf(LOG_LCP_BIT, "%s\n", inet_ntoa(dstipaddr)); 448 449 switch (mode) { 450 case MODE_REQ: 451 IpcpInfo.his_ipaddr = ipaddr; 452 IpcpInfo.want_ipaddr = dstipaddr; 453 bcopy(cp, ackp, length); 454 ackp += length; 455 break; 456 case MODE_NAK: 457 LogPrintf(LOG_LCP_BIT, "%s changing address: %s ", 458 tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 459 LogPrintf(LOG_LCP_BIT, "--> %s\n", inet_ntoa(ipaddr)); 460 IpcpInfo.want_ipaddr = ipaddr; 461 IpcpInfo.his_ipaddr = dstipaddr; 462 break; 463 case MODE_REJ: 464 IpcpInfo.his_reject |= (1 << type); 465 break; 466 } 467 break; 468 469 /* 470 * MS extensions for MS's PPP 471 */ 472 473#ifdef MSEXT 474 case TY_PRIMARY_DNS: /* MS PPP DNS negotiation hack */ 475 case TY_SECONDARY_DNS: 476 if( !Enabled( ConfMSExt ) ) { 477 LogPrintf( LOG_LCP, "MS NS req - rejected - msext disabled\n" ); 478 IpcpInfo.my_reject |= ( 1 << type ); 479 bcopy(cp, rejp, length); 480 rejp += length; 481 break; 482 } 483 switch( mode ){ 484 case MODE_REQ: 485 lp = (u_long *)(cp + 2); 486 dnsstuff.s_addr = *lp; 487 ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS)?1:0)].s_addr; 488 if( dnsstuff.s_addr != ms_info_req.s_addr ) 489 { 490 /* 491 So the client has got the DNS stuff wrong (first request) 492 so well tell 'em how it is 493 */ 494 bcopy( cp, nakp, 2 ); /* copy first two (type/length) */ 495 LogPrintf( LOG_LCP, "MS NS req %d:%s->%s - nak\n", 496 type, 497 inet_ntoa( dnsstuff ), 498 inet_ntoa( ms_info_req )); 499 bcopy( &ms_info_req, nakp+2, length ); 500 nakp += length; 501 break; 502 } 503 /* 504 Otherwise they have it right (this time) so we send 505 a ack packet back confirming it... end of story 506 */ 507 LogPrintf( LOG_LCP, "MS NS req %d:%s ok - ack\n", 508 type, 509 inet_ntoa( ms_info_req )); 510 bcopy( cp, ackp, length ); 511 ackp += length; 512 break; 513 case MODE_NAK: /* what does this mean?? */ 514 LogPrintf(LOG_LCP, "MS NS req %d - NAK??\n", type ); 515 break; 516 case MODE_REJ: /* confused?? me to :) */ 517 LogPrintf(LOG_LCP, "MS NS req %d - REJ??\n", type ); 518 break; 519 } 520 break; 521 522 case TY_PRIMARY_NBNS: /* MS PPP NetBIOS nameserver hack */ 523 case TY_SECONDARY_NBNS: 524 if( !Enabled( ConfMSExt ) ) { 525 LogPrintf( LOG_LCP, "MS NBNS req - rejected - msext disabled\n" ); 526 IpcpInfo.my_reject |= ( 1 << type ); 527 bcopy( cp, rejp, length ); 528 rejp += length; 529 break; 530 } 531 switch( mode ){ 532 case MODE_REQ: 533 lp = (u_long *)(cp + 2); 534 dnsstuff.s_addr = *lp; 535 ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS)?1:0)].s_addr; 536 if( dnsstuff.s_addr != ms_info_req.s_addr ) 537 { 538 bcopy( cp, nakp, 2 ); 539 bcopy( &ms_info_req.s_addr , nakp+2, length ); 540 LogPrintf( LOG_LCP, "MS NBNS req %d:%s->%s - nak\n", 541 type, 542 inet_ntoa( dnsstuff ), 543 inet_ntoa( ms_info_req )); 544 nakp += length; 545 break; 546 } 547 LogPrintf( LOG_LCP, "MS NBNS req %d:%s ok - ack\n", 548 type, 549 inet_ntoa( ms_info_req )); 550 bcopy( cp, ackp, length ); 551 ackp += length; 552 break; 553 case MODE_NAK: 554 LogPrintf( LOG_LCP, "MS NBNS req %d - NAK??\n", type ); 555 break; 556 case MODE_REJ: 557 LogPrintf( LOG_LCP, "MS NBNS req %d - REJ??\n", type ); 558 break; 559 } 560 break; 561 562#endif /* MSEXT */ 563 564 default: 565 IpcpInfo.my_reject |= (1 << type); 566 bcopy(cp, rejp, length); 567 rejp += length; 568 break; 569 } 570 plen -= length; 571 cp += length; 572 } 573} 574 575void 576IpcpInput(struct mbuf *bp) 577{ 578 FsmInput(&IpcpFsm, bp); 579} 580