ipcp.c revision 18752
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 39extern void PutConfValue(); 40extern void Prompt(); 41extern struct in_addr ifnetmask; 42 43struct ipcpstate IpcpInfo; 44struct in_range DefMyAddress, DefHisAddress, DefTriggerAddress; 45 46#ifdef MSEXT 47struct in_addr ns_entries[2], nbns_entries[2]; 48#endif /* MSEXT */ 49 50static void IpcpSendConfigReq __P((struct fsm *)); 51static void IpcpSendTerminateAck __P((struct fsm *)); 52static void IpcpSendTerminateReq __P((struct fsm *)); 53static void IpcpDecodeConfig __P((u_char *, int, int)); 54static void IpcpLayerStart __P((struct fsm *)); 55static void IpcpLayerFinish __P((struct fsm *)); 56static void IpcpLayerUp __P((struct fsm *)); 57static void IpcpLayerDown __P((struct fsm *)); 58static void IpcpInitRestartCounter __P((struct fsm *)); 59 60struct pppTimer IpcpReportTimer; 61 62static int lastInOctets, lastOutOctets; 63 64#define REJECTED(p, x) (p->his_reject & (1<<x)) 65 66struct 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 88static 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 */ 96static void 97IpcpReportFunc() 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 109static void 110IpcpStartReport() 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 120void 121ReportIpcpStatus() 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 141void 142IpcpDefAddress() 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 158void 159IpcpInit() 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 190static void 191IpcpInitRestartCounter(fp) 192struct fsm *fp; 193{ 194 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 195 fp->restart = 5; 196} 197 198static void 199IpcpSendConfigReq(fp) 200struct 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 218static void 219IpcpSendTerminateReq(fp) 220struct fsm *fp; 221{ 222 /* XXX: No code yet */ 223} 224 225static void 226IpcpSendTerminateAck(fp) 227struct fsm *fp; 228{ 229 LogPrintf(LOG_LCP_BIT, " %s: SendTerminateAck\n", fp->name); 230 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 231} 232 233static void 234IpcpLayerStart(fp) 235struct fsm *fp; 236{ 237 LogPrintf(LOG_LCP_BIT, "%s: LayerStart.\n", fp->name); 238} 239 240static void 241IpcpLayerFinish(fp) 242struct fsm *fp; 243{ 244 LogPrintf(LOG_LCP_BIT, "%s: LayerFinish.\n", fp->name); 245 LcpClose(); 246 NewPhase(PHASE_TERMINATE); 247} 248 249static void 250IpcpLayerDown(fp) 251struct 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 */ 260static void 261IpcpLayerUp(fp) 262struct 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 279void 280IpcpUp() 281{ 282 FsmUp(&IpcpFsm); 283 LogPrintf(LOG_LCP_BIT, "IPCP Up event!!\n"); 284} 285 286void 287IpcpOpen() 288{ 289 FsmOpen(&IpcpFsm); 290} 291 292static int 293AcceptableAddr(prange, ipaddr) 294struct in_range *prange; 295struct 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 308static void 309IpcpDecodeConfig(cp, plen, mode) 310u_char *cp; 311int plen; 312int 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 566void 567IpcpInput(struct mbuf *bp) 568{ 569 FsmInput(&IpcpFsm, bp); 570} 571