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