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