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