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.3 1995/03/11 15:18:44 amurai 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; 45 46 static void IpcpSendConfigReq __P((struct fsm *)); 47 static void IpcpSendTerminateAck __P((struct fsm *)); 48 static void IpcpSendTerminateReq __P((struct fsm *)); 49 static void IpcpDecodeConfig __P((u_char *, int, int)); 50 static void IpcpLayerStart __P((struct fsm *)); 51 static void IpcpLayerFinish __P((struct fsm *)); 52 static void IpcpLayerUp __P((struct fsm *)); 53 static void IpcpLayerDown __P((struct fsm *)); 54 static void IpcpInitRestartCounter __P((struct fsm *)); 55 56 struct pppTimer IpcpReportTimer; 57 58 static int lastInOctets, lastOutOctets; 59 60 #define REJECTED(p, x) (p->his_reject & (1<<x)) 61 62 struct fsm IpcpFsm = { 63 "IPCP", 64 PROTO_IPCP, 65 IPCP_MAXCODE, 66 OPEN_ACTIVE, 67 ST_INITIAL, 68 0, 0, 0, 69 70 0, 71 { 0, 0, 0, NULL, NULL, NULL }, 72 73 IpcpLayerUp, 74 IpcpLayerDown, 75 IpcpLayerStart, 76 IpcpLayerFinish, 77 IpcpInitRestartCounter, 78 IpcpSendConfigReq, 79 IpcpSendTerminateReq, 80 IpcpSendTerminateAck, 81 IpcpDecodeConfig, 82 }; 83 84 static char *cftypes[] = { 85 "???", "IPADDRS", "COMPPROTO", "IPADDR", 86 }; 87 88 /* 89 * Function called every second. Updates connection period and idle period, 90 * also update LQR information. 91 */ 92 static void 93 IpcpReportFunc() 94 { 95 ipConnectSecs++; 96 if (lastInOctets == ipInOctets && lastOutOctets == ipOutOctets) 97 ipIdleSecs++; 98 lastInOctets = ipInOctets; 99 lastOutOctets = ipOutOctets; 100 StopTimer(&IpcpReportTimer); 101 IpcpReportTimer.state = TIMER_STOPPED; 102 StartTimer(&IpcpReportTimer); 103 } 104 105 static void 106 IpcpStartReport() 107 { 108 ipIdleSecs = ipConnectSecs = 0; 109 StopTimer(&IpcpReportTimer); 110 IpcpReportTimer.state = TIMER_STOPPED; 111 IpcpReportTimer.load = SECTICKS; 112 IpcpReportTimer.func = IpcpReportFunc; 113 StartTimer(&IpcpReportTimer); 114 } 115 116 void 117 ReportIpcpStatus() 118 { 119 struct ipcpstate *icp = &IpcpInfo; 120 struct fsm *fp = &IpcpFsm; 121 122 printf("%s [%s]\n", fp->name, StateNames[fp->state]); 123 printf(" his side: %s, %x\n", 124 inet_ntoa(icp->his_ipaddr), icp->his_compproto); 125 printf(" my side: %s, %x\n", 126 inet_ntoa(icp->want_ipaddr), icp->want_compproto); 127 printf("connected: %d secs, idle: %d secs\n\n", ipConnectSecs, ipIdleSecs); 128 printf("Defaults: My Address: %s/%d ", 129 inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width); 130 printf("His Address: %s/%d\n", 131 inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width); 132 } 133 134 void 135 IpcpDefAddress() 136 { 137 struct hostent *hp; 138 char name[200]; 139 140 bzero(&DefMyAddress, sizeof(DefMyAddress)); 141 bzero(&DefHisAddress, sizeof(DefHisAddress)); 142 if (gethostname(name, sizeof(name)) == 0) { 143 hp = gethostbyname(name); 144 if (hp && hp->h_addrtype == AF_INET) { 145 bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length); 146 } 147 } 148 } 149 150 void 151 IpcpInit() 152 { 153 struct ipcpstate *icp = &IpcpInfo; 154 155 FsmInit(&IpcpFsm); 156 bzero(icp, sizeof(struct ipcpstate)); 157 if ((mode & MODE_DEDICATED) && !dstsystem) { 158 icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0; 159 } else { 160 icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; 161 icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; 162 } 163 if (icp->want_ipaddr.s_addr == 0) 164 icp->want_ipaddr.s_addr = htonl(0xc0000001); 165 if (Enabled(ConfVjcomp)) 166 icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8); 167 else 168 icp->want_compproto = 0; 169 icp->heis1172 = 0; 170 IpcpFsm.maxconfig = 10; 171 } 172 173 static void 174 IpcpInitRestartCounter(fp) 175 struct fsm *fp; 176 { 177 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 178 fp->restart = 5; 179 } 180 181 static void 182 IpcpSendConfigReq(fp) 183 struct fsm *fp; 184 { 185 u_char *cp; 186 struct ipcpstate *icp = &IpcpInfo; 187 188 cp = ReqBuff; 189 LogPrintf(LOG_LCP, "%s: SendConfigReq\n", fp->name); 190 if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR)) 191 PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr)); 192 if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) { 193 if (icp->heis1172) 194 PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16); 195 else 196 PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto); 197 } 198 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 199 } 200 201 static void 202 IpcpSendTerminateReq(fp) 203 struct fsm *fp; 204 { 205 /* XXX: No code yet */ 206 } 207 208 static void 209 IpcpSendTerminateAck(fp) 210 struct fsm *fp; 211 { 212 LogPrintf(LOG_LCP, " %s: SendTerminateAck\n", fp->name); 213 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 214 } 215 216 static void 217 IpcpLayerStart(fp) 218 struct fsm *fp; 219 { 220 LogPrintf(LOG_LCP, "%s: LayerStart.\n", fp->name); 221 } 222 223 static void 224 IpcpLayerFinish(fp) 225 struct fsm *fp; 226 { 227 LogPrintf(LOG_LCP, "%s: LayerFinish.\n", fp->name); 228 LcpClose(); 229 NewPhase(PHASE_TERMINATE); 230 } 231 232 static void 233 IpcpLayerDown(fp) 234 struct fsm *fp; 235 { 236 LogPrintf(LOG_LCP, "%s: LayerDown.\n", fp->name); 237 StopTimer(&IpcpReportTimer); 238 } 239 240 /* 241 * Called when IPCP has reached to OPEN state 242 */ 243 static void 244 IpcpLayerUp(fp) 245 struct fsm *fp; 246 { 247 char tbuff[100]; 248 249 #ifdef VERBOSE 250 fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state); 251 #endif 252 Prompt(1); 253 LogPrintf(LOG_LCP, "%s: LayerUp.\n", fp->name); 254 sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr)); 255 LogPrintf(LOG_LCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); 256 OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask); 257 OsLinkup(); 258 IpcpStartReport(); 259 StartIdleTimer(); 260 } 261 262 void 263 IpcpUp() 264 { 265 FsmUp(&IpcpFsm); 266 LogPrintf(LOG_LCP, "IPCP Up event!!\n"); 267 } 268 269 void 270 IpcpOpen() 271 { 272 FsmOpen(&IpcpFsm); 273 } 274 275 static int 276 AcceptableAddr(prange, ipaddr) 277 struct in_range *prange; 278 struct in_addr ipaddr; 279 { 280 #ifdef DEBUG 281 logprintf("requested = %x ", htonl(ipaddr.s_addr)); 282 logprintf("range = %x", htonl(prange->ipaddr.s_addr)); 283 logprintf("/%x\n", htonl(prange->mask.s_addr)); 284 logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr), 285 htonl(ipaddr.s_addr & prange->mask.s_addr)); 286 #endif 287 return((prange->ipaddr.s_addr & prange->mask.s_addr) == 288 (ipaddr.s_addr & prange->mask.s_addr)); 289 } 290 291 static void 292 IpcpDecodeConfig(cp, plen, mode) 293 u_char *cp; 294 int plen; 295 int mode; 296 { 297 int type, length; 298 u_long *lp, compproto; 299 struct compreq *pcomp; 300 struct in_addr ipaddr, dstipaddr; 301 char tbuff[100]; 302 303 ackp = AckBuff; 304 nakp = NakBuff; 305 rejp = RejBuff; 306 307 while (plen >= sizeof(struct fsmconfig)) { 308 if (plen < 0) 309 break; 310 type = *cp; 311 length = cp[1]; 312 if (type <= TY_IPADDR) 313 sprintf(tbuff, " %s[%d] ", cftypes[type], length); 314 else 315 sprintf(tbuff, " "); 316 317 switch (type) { 318 case TY_IPADDR: /* RFC1332 */ 319 lp = (u_long *)(cp + 2); 320 ipaddr.s_addr = *lp; 321 LogPrintf(LOG_LCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); 322 323 switch (mode) { 324 case MODE_REQ: 325 if (!AcceptableAddr(&DefHisAddress, ipaddr)) { 326 /* 327 * If destination address is not acceptable, insist to use 328 * what we want to use. 329 */ 330 bcopy(cp, nakp, 2); 331 bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length); 332 nakp += length; 333 break; 334 335 } 336 IpcpInfo.his_ipaddr = ipaddr; 337 bcopy(cp, ackp, length); 338 ackp += length; 339 break; 340 case MODE_NAK: 341 if (AcceptableAddr(&DefMyAddress, ipaddr)) { 342 /* 343 * Use address suggested by peer. 344 */ 345 sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 346 LogPrintf(LOG_LCP, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr)); 347 IpcpInfo.want_ipaddr = ipaddr; 348 } 349 break; 350 case MODE_REJ: 351 IpcpInfo.his_reject |= (1 << type); 352 break; 353 } 354 break; 355 case TY_COMPPROTO: 356 lp = (u_long *)(cp + 2); 357 compproto = htonl(*lp); 358 LogPrintf(LOG_LCP, "%s %08x\n", tbuff, compproto); 359 360 switch (mode) { 361 case MODE_REQ: 362 if (!Acceptable(ConfVjcomp)) { 363 bcopy(cp, rejp, length); 364 rejp += length; 365 } else { 366 pcomp = (struct compreq *)(cp + 2); 367 switch (length) { 368 case 4: /* RFC1172 */ 369 if (ntohs(pcomp->proto) == PROTO_VJCOMP) { 370 logprintf("** Peer is speaking RFC1172 compression protocol **\n"); 371 IpcpInfo.heis1172 = 1; 372 IpcpInfo.his_compproto = compproto; 373 bcopy(cp, ackp, length); 374 ackp += length; 375 } else { 376 bcopy(cp, nakp, 2); 377 pcomp->proto = htons(PROTO_VJCOMP); 378 bcopy(&pcomp, nakp + 2, 2); 379 nakp += length; 380 } 381 break; 382 case 6: /* RFC1332 */ 383 if (ntohs(pcomp->proto) == PROTO_VJCOMP 384 && pcomp->slots < MAX_STATES && pcomp->slots > 2) { 385 IpcpInfo.his_compproto = compproto; 386 IpcpInfo.heis1172 = 0; 387 bcopy(cp, ackp, length); 388 ackp += length; 389 } else { 390 bcopy(cp, nakp, 2); 391 pcomp->proto = htons(PROTO_VJCOMP); 392 pcomp->slots = MAX_STATES - 1; 393 pcomp->compcid = 0; 394 bcopy(&pcomp, nakp + 2, sizeof(pcomp)); 395 nakp += length; 396 } 397 break; 398 default: 399 bcopy(cp, rejp, length); 400 rejp += length; 401 break; 402 } 403 } 404 break; 405 case MODE_NAK: 406 LogPrintf(LOG_LCP, "%s changing compproto: %08x --> %08x\n", 407 tbuff, IpcpInfo.want_compproto, compproto); 408 IpcpInfo.want_compproto = compproto; 409 break; 410 case MODE_REJ: 411 IpcpInfo.his_reject |= (1 << type); 412 break; 413 } 414 break; 415 case TY_IPADDRS: /* RFC1172 */ 416 lp = (u_long *)(cp + 2); 417 ipaddr.s_addr = *lp; 418 lp = (u_long *)(cp + 6); 419 dstipaddr.s_addr = *lp; 420 LogPrintf(LOG_LCP, "%s %s, ", tbuff, inet_ntoa(ipaddr)); 421 LogPrintf(LOG_LCP, "%s\n", inet_ntoa(dstipaddr)); 422 423 switch (mode) { 424 case MODE_REQ: 425 IpcpInfo.his_ipaddr = ipaddr; 426 IpcpInfo.want_ipaddr = dstipaddr; 427 bcopy(cp, ackp, length); 428 ackp += length; 429 break; 430 case MODE_NAK: 431 LogPrintf(LOG_LCP, "%s changing address: %s ", 432 tbuff, inet_ntoa(IpcpInfo.want_ipaddr)); 433 LogPrintf(LOG_LCP, "--> %s\n", inet_ntoa(ipaddr)); 434 IpcpInfo.want_ipaddr = ipaddr; 435 IpcpInfo.his_ipaddr = dstipaddr; 436 break; 437 case MODE_REJ: 438 IpcpInfo.his_reject |= (1 << type); 439 break; 440 } 441 break; 442 default: 443 IpcpInfo.my_reject |= (1 << type); 444 bcopy(cp, rejp, length); 445 rejp += length; 446 break; 447 } 448 plen -= length; 449 cp += length; 450 } 451 } 452 453 void 454 IpcpInput(struct mbuf *bp) 455 { 456 FsmInput(&IpcpFsm, bp); 457 } 458