xref: /freebsd/usr.sbin/ppp/ipcp.c (revision 61afd5bb22d787b0641523e7b9b95c964d669bd5)
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.9 1996/10/06 13:32:28 jkh 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 
40 extern void PutConfValue();
41 extern void Prompt();
42 extern struct in_addr ifnetmask;
43 
44 struct ipcpstate IpcpInfo;
45 struct in_range DefMyAddress, DefHisAddress, DefTriggerAddress;
46 
47 #ifdef MSEXT
48 struct in_addr ns_entries[2], nbns_entries[2];
49 #endif /* MSEXT */
50 
51 static void IpcpSendConfigReq __P((struct fsm *));
52 static void IpcpSendTerminateAck __P((struct fsm *));
53 static void IpcpSendTerminateReq __P((struct fsm *));
54 static void IpcpDecodeConfig __P((u_char *, int, int));
55 static void IpcpLayerStart __P((struct fsm *));
56 static void IpcpLayerFinish __P((struct fsm *));
57 static void IpcpLayerUp __P((struct fsm *));
58 static void IpcpLayerDown __P((struct fsm *));
59 static void IpcpInitRestartCounter __P((struct fsm *));
60 
61 struct pppTimer IpcpReportTimer;
62 
63 static int lastInOctets, lastOutOctets;
64 
65 #define	REJECTED(p, x)	(p->his_reject & (1<<x))
66 
67 struct 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 
89 static 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  */
97 static void
98 IpcpReportFunc()
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 
110 static void
111 IpcpStartReport()
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 
121 void
122 ReportIpcpStatus()
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 }
141 
142 void
143 IpcpDefAddress()
144 {
145   struct hostent *hp;
146   char name[200];
147 
148   bzero(&DefMyAddress, sizeof(DefMyAddress));
149   bzero(&DefHisAddress, sizeof(DefHisAddress));
150   bzero(&DefTriggerAddress, sizeof(DefTriggerAddress));
151   if (gethostname(name, sizeof(name)) == 0) {
152       hp = gethostbyname(name);
153       if (hp && hp->h_addrtype == AF_INET) {
154 	bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length);
155       }
156   }
157 }
158 
159 void
160 IpcpInit()
161 {
162   struct ipcpstate *icp = &IpcpInfo;
163 
164   FsmInit(&IpcpFsm);
165   bzero(icp, sizeof(struct ipcpstate));
166   if ((mode & MODE_DEDICATED) && !dstsystem) {
167     icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0;
168   } else {
169     icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
170     icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
171   }
172 
173   /*
174    * Some implementation of PPP are:
175    *  Starting a negotiaion by require sending *special* value as my address,
176    *  even though standard of PPP is defined full negotiation based.
177    *  (e.g. "0.0.0.0" or Not "0.0.0.0")
178    */
179   if ( icp->want_ipaddr.s_addr == 0 ) {
180     icp->want_ipaddr.s_addr = DefTriggerAddress.ipaddr.s_addr;
181   }
182 
183   if (Enabled(ConfVjcomp))
184     icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8);
185   else
186     icp->want_compproto = 0;
187   icp->heis1172 = 0;
188   IpcpFsm.maxconfig = 10;
189 }
190 
191 static void
192 IpcpInitRestartCounter(fp)
193 struct fsm *fp;
194 {
195   fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
196   fp->restart = 5;
197 }
198 
199 static void
200 IpcpSendConfigReq(fp)
201 struct fsm *fp;
202 {
203   u_char *cp;
204   struct ipcpstate *icp = &IpcpInfo;
205 
206   cp = ReqBuff;
207   LogPrintf(LOG_LCP_BIT, "%s: SendConfigReq\n", fp->name);
208   if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR))
209     PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr));
210   if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) {
211     if (icp->heis1172)
212       PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16);
213     else
214       PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto);
215   }
216   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
217 }
218 
219 static void
220 IpcpSendTerminateReq(fp)
221 struct fsm *fp;
222 {
223   /* XXX: No code yet */
224 }
225 
226 static void
227 IpcpSendTerminateAck(fp)
228 struct fsm *fp;
229 {
230   LogPrintf(LOG_LCP_BIT, "  %s: SendTerminateAck\n", fp->name);
231   FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
232 }
233 
234 static void
235 IpcpLayerStart(fp)
236 struct fsm *fp;
237 {
238   LogPrintf(LOG_LCP_BIT, "%s: LayerStart.\n", fp->name);
239 }
240 
241 static void
242 IpcpLayerFinish(fp)
243 struct fsm *fp;
244 {
245   LogPrintf(LOG_LCP_BIT, "%s: LayerFinish.\n", fp->name);
246   LcpClose();
247   NewPhase(PHASE_TERMINATE);
248 }
249 
250 static void
251 IpcpLayerDown(fp)
252 struct fsm *fp;
253 {
254   LogPrintf(LOG_LCP_BIT, "%s: LayerDown.\n", fp->name);
255   StopTimer(&IpcpReportTimer);
256 }
257 
258 /*
259  *  Called when IPCP has reached to OPEN state
260  */
261 static void
262 IpcpLayerUp(fp)
263 struct fsm *fp;
264 {
265   char tbuff[100];
266 
267 #ifdef VERBOSE
268   fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state);
269 #endif
270   Prompt(1);
271   LogPrintf(LOG_LCP_BIT, "%s: LayerUp.\n", fp->name);
272   sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr));
273   LogPrintf(LOG_LCP_BIT|LOG_LINK_BIT, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
274   OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
275   OsLinkup();
276   IpcpStartReport();
277   StartIdleTimer();
278   if (mode & MODE_ALIAS)
279     SetAliasAddress(IpcpInfo.want_ipaddr);
280 }
281 
282 void
283 IpcpUp()
284 {
285   FsmUp(&IpcpFsm);
286   LogPrintf(LOG_LCP_BIT, "IPCP Up event!!\n");
287 }
288 
289 void
290 IpcpOpen()
291 {
292   FsmOpen(&IpcpFsm);
293 }
294 
295 static int
296 AcceptableAddr(prange, ipaddr)
297 struct in_range *prange;
298 struct in_addr ipaddr;
299 {
300 #ifdef DEBUG
301   logprintf("requested = %x ", htonl(ipaddr.s_addr));
302   logprintf("range = %x", htonl(prange->ipaddr.s_addr));
303   logprintf("/%x\n", htonl(prange->mask.s_addr));
304   logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr),
305     htonl(ipaddr.s_addr & prange->mask.s_addr));
306 #endif
307   return((prange->ipaddr.s_addr & prange->mask.s_addr) ==
308 	(ipaddr.s_addr & prange->mask.s_addr));
309 }
310 
311 static void
312 IpcpDecodeConfig(cp, plen, mode)
313 u_char *cp;
314 int plen;
315 int mode;
316 {
317   int type, length;
318   u_long *lp, compproto;
319   struct compreq *pcomp;
320   struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req;
321   char tbuff[100];
322 
323   ackp = AckBuff;
324   nakp = NakBuff;
325   rejp = RejBuff;
326 
327   while (plen >= sizeof(struct fsmconfig)) {
328     if (plen < 0)
329       break;
330     type = *cp;
331     length = cp[1];
332     if (type <= TY_IPADDR)
333       sprintf(tbuff, " %s[%d] ", cftypes[type], length);
334     else
335       sprintf(tbuff, " ");
336 
337     switch (type) {
338     case TY_IPADDR:		/* RFC1332 */
339       lp = (u_long *)(cp + 2);
340       ipaddr.s_addr = *lp;
341       LogPrintf(LOG_LCP_BIT, "%s %s\n", tbuff, inet_ntoa(ipaddr));
342 
343       switch (mode) {
344       case MODE_REQ:
345 	if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
346           /*
347            * If destination address is not acceptable, insist to use
348            * what we want to use.
349            */
350 	  bcopy(cp, nakp, 2);
351           bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length);
352           nakp += length;
353           break;
354 
355 	}
356 	IpcpInfo.his_ipaddr = ipaddr;
357 	bcopy(cp, ackp, length);
358 	ackp += length;
359 	break;
360       case MODE_NAK:
361 	if (AcceptableAddr(&DefMyAddress, ipaddr)) {
362           /*
363            * Use address suggested by peer.
364            */
365 	  sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
366 	  LogPrintf(LOG_LCP_BIT, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr));
367 	  IpcpInfo.want_ipaddr = ipaddr;
368 	}
369 	break;
370       case MODE_REJ:
371 	IpcpInfo.his_reject |= (1 << type);
372 	break;
373       }
374       break;
375     case TY_COMPPROTO:
376       lp = (u_long *)(cp + 2);
377       compproto = htonl(*lp);
378       LogPrintf(LOG_LCP_BIT, "%s %08x\n", tbuff, compproto);
379 
380       switch (mode) {
381       case MODE_REQ:
382 	if (!Acceptable(ConfVjcomp)) {
383 	  bcopy(cp, rejp, length);
384 	  rejp += length;
385 	} else {
386 	  pcomp = (struct compreq *)(cp + 2);
387 	  switch (length) {
388 	  case 4:	/* RFC1172 */
389 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
390 	      logprintf("** Peer is speaking RFC1172 compression protocol **\n");
391 	      IpcpInfo.heis1172 = 1;
392 	      IpcpInfo.his_compproto = compproto;
393 	      bcopy(cp, ackp, length);
394 	      ackp += length;
395 	    } else {
396 	      bcopy(cp, nakp, 2);
397 	      pcomp->proto = htons(PROTO_VJCOMP);
398 	      bcopy(&pcomp, nakp + 2, 2);
399 	      nakp += length;
400 	    }
401 	    break;
402 	  case 6: 	/* RFC1332 */
403 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
404 	        && pcomp->slots < MAX_STATES && pcomp->slots > 2) {
405 	      IpcpInfo.his_compproto = compproto;
406 	      IpcpInfo.heis1172 = 0;
407 	      bcopy(cp, ackp, length);
408 	      ackp += length;
409 	    } else {
410 	      bcopy(cp, nakp, 2);
411 	      pcomp->proto = htons(PROTO_VJCOMP);
412 	      pcomp->slots = MAX_STATES - 1;
413 	      pcomp->compcid = 0;
414 	      bcopy(&pcomp, nakp + 2, sizeof(pcomp));
415 	      nakp += length;
416 	    }
417 	    break;
418 	  default:
419 	    bcopy(cp, rejp, length);
420 	    rejp += length;
421 	    break;
422 	  }
423 	}
424 	break;
425       case MODE_NAK:
426 	LogPrintf(LOG_LCP_BIT, "%s changing compproto: %08x --> %08x\n",
427 	  tbuff, IpcpInfo.want_compproto, compproto);
428 	IpcpInfo.want_compproto = compproto;
429 	break;
430       case MODE_REJ:
431 	IpcpInfo.his_reject |= (1 << type);
432 	break;
433       }
434       break;
435     case TY_IPADDRS:	/* RFC1172 */
436       lp = (u_long *)(cp + 2);
437       ipaddr.s_addr = *lp;
438       lp = (u_long *)(cp + 6);
439       dstipaddr.s_addr = *lp;
440       LogPrintf(LOG_LCP_BIT, "%s %s, ", tbuff, inet_ntoa(ipaddr));
441       LogPrintf(LOG_LCP_BIT, "%s\n", inet_ntoa(dstipaddr));
442 
443       switch (mode) {
444       case MODE_REQ:
445 	IpcpInfo.his_ipaddr = ipaddr;
446 	IpcpInfo.want_ipaddr = dstipaddr;
447 	bcopy(cp, ackp, length);
448 	ackp += length;
449 	break;
450       case MODE_NAK:
451 	LogPrintf(LOG_LCP_BIT, "%s changing address: %s ",
452 	  tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
453 	LogPrintf(LOG_LCP_BIT, "--> %s\n", inet_ntoa(ipaddr));
454 	IpcpInfo.want_ipaddr = ipaddr;
455 	IpcpInfo.his_ipaddr = dstipaddr;
456 	break;
457       case MODE_REJ:
458 	IpcpInfo.his_reject |= (1 << type);
459 	break;
460       }
461       break;
462 
463  /*
464   * MS extensions for MS's PPP
465   */
466 
467 #ifdef MSEXT
468     case TY_PRIMARY_DNS:   /* MS PPP DNS negotiation hack */
469     case TY_SECONDARY_DNS:
470       if( !Enabled( ConfMSExt ) ) {
471 	LogPrintf( LOG_LCP, "MS NS req - rejected - msext disabled\n" );
472 	IpcpInfo.my_reject |= ( 1 << type );
473 	bcopy(cp, rejp, length);
474 	rejp += length;
475 	break;
476       }
477       switch( mode ){
478       case MODE_REQ:
479 	lp = (u_long *)(cp + 2);
480 	dnsstuff.s_addr = *lp;
481 	ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS)?1:0)].s_addr;
482 	if( dnsstuff.s_addr != ms_info_req.s_addr )
483 	{
484 	  /*
485 	   So the client has got the DNS stuff wrong (first request)
486 	   so well tell 'em how it is
487 	  */
488 	  bcopy( cp, nakp, 2 );  /* copy first two (type/length) */
489 	  LogPrintf( LOG_LCP, "MS NS req %d:%s->%s - nak\n",
490 		type,
491 		inet_ntoa( dnsstuff ),
492 		inet_ntoa( ms_info_req ));
493 	  bcopy( &ms_info_req, nakp+2, length );
494 	  nakp += length;
495 	  break;
496 	}
497 	  /*
498 	   Otherwise they have it right (this time) so we send
499 	   a ack packet back confirming it... end of story
500 	  */
501 	LogPrintf( LOG_LCP, "MS NS req %d:%s ok - ack\n",
502 		type,
503 		inet_ntoa( ms_info_req ));
504 	bcopy( cp, ackp, length );
505 	ackp += length;
506 	break;
507       case MODE_NAK: /* what does this mean?? */
508 	LogPrintf(LOG_LCP, "MS NS req %d - NAK??\n", type );
509 	break;
510       case MODE_REJ: /* confused?? me to :) */
511 	LogPrintf(LOG_LCP, "MS NS req %d - REJ??\n", type );
512 	break;
513       }
514       break;
515 
516     case TY_PRIMARY_NBNS:   /* MS PPP NetBIOS nameserver hack */
517     case TY_SECONDARY_NBNS:
518     if( !Enabled( ConfMSExt ) ) {
519       LogPrintf( LOG_LCP, "MS NBNS req - rejected - msext disabled\n" );
520       IpcpInfo.my_reject |= ( 1 << type );
521       bcopy( cp, rejp, length );
522       rejp += length;
523       break;
524     }
525       switch( mode ){
526       case MODE_REQ:
527 	lp = (u_long *)(cp + 2);
528 	dnsstuff.s_addr = *lp;
529 	ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS)?1:0)].s_addr;
530 	if( dnsstuff.s_addr != ms_info_req.s_addr )
531 	{
532 	  bcopy( cp, nakp, 2 );
533 	  bcopy( &ms_info_req.s_addr , nakp+2, length );
534 	  LogPrintf( LOG_LCP, "MS NBNS req %d:%s->%s - nak\n",
535 		type,
536 		inet_ntoa( dnsstuff ),
537 		inet_ntoa( ms_info_req ));
538 	  nakp += length;
539 	  break;
540 	}
541 	LogPrintf( LOG_LCP, "MS NBNS req %d:%s ok - ack\n",
542 		type,
543 		inet_ntoa( ms_info_req ));
544 	bcopy( cp, ackp, length );
545 	ackp += length;
546 	break;
547       case MODE_NAK:
548 	LogPrintf( LOG_LCP, "MS NBNS req %d - NAK??\n", type );
549 	break;
550       case MODE_REJ:
551 	LogPrintf( LOG_LCP, "MS NBNS req %d - REJ??\n", type );
552 	break;
553       }
554       break;
555 
556 #endif /* MSEXT */
557 
558     default:
559       IpcpInfo.my_reject |= (1 << type);
560       bcopy(cp, rejp, length);
561       rejp += length;
562       break;
563     }
564     plen -= length;
565     cp += length;
566   }
567 }
568 
569 void
570 IpcpInput(struct mbuf *bp)
571 {
572   FsmInput(&IpcpFsm, bp);
573 }
574