xref: /freebsd/usr.sbin/ppp/ipcp.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
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.5 1995/07/04 02:57:11 davidg 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 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:\n");
129   printf(" My Address:  %s/%d\n",
130      inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width);
131   printf(" His Address: %s/%d\n",
132      inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width);
133   printf(" Negotiation: %s/%d\n",
134      inet_ntoa(DefTriggerAddress.ipaddr), DefTriggerAddress.width);
135 }
136 
137 void
138 IpcpDefAddress()
139 {
140   struct hostent *hp;
141   char name[200];
142 
143   bzero(&DefMyAddress, sizeof(DefMyAddress));
144   bzero(&DefHisAddress, sizeof(DefHisAddress));
145   bzero(&DefTriggerAddress, sizeof(DefTriggerAddress));
146   if (gethostname(name, sizeof(name)) == 0) {
147       hp = gethostbyname(name);
148       if (hp && hp->h_addrtype == AF_INET) {
149 	bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length);
150       }
151   }
152 }
153 
154 void
155 IpcpInit()
156 {
157   struct ipcpstate *icp = &IpcpInfo;
158 
159   FsmInit(&IpcpFsm);
160   bzero(icp, sizeof(struct ipcpstate));
161   if ((mode & MODE_DEDICATED) && !dstsystem) {
162     icp->want_ipaddr.s_addr = icp->his_ipaddr.s_addr = 0;
163   } else {
164     icp->want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr;
165     icp->his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr;
166   }
167 
168   /*
169    * Some implementation of PPP are:
170    *  Starting a negotiaion by require sending *special* value as my address,
171    *  even though standard of PPP is defined full negotiation based.
172    *  (e.g. "0.0.0.0" or Not "0.0.0.0")
173    */
174   if ( icp->want_ipaddr.s_addr == 0 ) {
175     icp->want_ipaddr.s_addr = DefTriggerAddress.ipaddr.s_addr;
176   }
177 
178   if (Enabled(ConfVjcomp))
179     icp->want_compproto = (PROTO_VJCOMP << 16) | ((MAX_STATES - 1) << 8);
180   else
181     icp->want_compproto = 0;
182   icp->heis1172 = 0;
183   IpcpFsm.maxconfig = 10;
184 }
185 
186 static void
187 IpcpInitRestartCounter(fp)
188 struct fsm *fp;
189 {
190   fp->FsmTimer.load = VarRetryTimeout * SECTICKS;
191   fp->restart = 5;
192 }
193 
194 static void
195 IpcpSendConfigReq(fp)
196 struct fsm *fp;
197 {
198   u_char *cp;
199   struct ipcpstate *icp = &IpcpInfo;
200 
201   cp = ReqBuff;
202   LogPrintf(LOG_LCP, "%s: SendConfigReq\n", fp->name);
203   if (!DEV_IS_SYNC || !REJECTED(icp, TY_IPADDR))
204     PutConfValue(&cp, cftypes, TY_IPADDR, 6, ntohl(icp->want_ipaddr.s_addr));
205   if (icp->want_compproto && !REJECTED(icp, TY_COMPPROTO)) {
206     if (icp->heis1172)
207       PutConfValue(&cp, cftypes, TY_COMPPROTO, 4, icp->want_compproto >> 16);
208     else
209       PutConfValue(&cp, cftypes, TY_COMPPROTO, 6, icp->want_compproto);
210   }
211   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff);
212 }
213 
214 static void
215 IpcpSendTerminateReq(fp)
216 struct fsm *fp;
217 {
218   /* XXX: No code yet */
219 }
220 
221 static void
222 IpcpSendTerminateAck(fp)
223 struct fsm *fp;
224 {
225   LogPrintf(LOG_LCP, "  %s: SendTerminateAck\n", fp->name);
226   FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
227 }
228 
229 static void
230 IpcpLayerStart(fp)
231 struct fsm *fp;
232 {
233   LogPrintf(LOG_LCP, "%s: LayerStart.\n", fp->name);
234 }
235 
236 static void
237 IpcpLayerFinish(fp)
238 struct fsm *fp;
239 {
240   LogPrintf(LOG_LCP, "%s: LayerFinish.\n", fp->name);
241   LcpClose();
242   NewPhase(PHASE_TERMINATE);
243 }
244 
245 static void
246 IpcpLayerDown(fp)
247 struct fsm *fp;
248 {
249   LogPrintf(LOG_LCP, "%s: LayerDown.\n", fp->name);
250   StopTimer(&IpcpReportTimer);
251 }
252 
253 /*
254  *  Called when IPCP has reached to OPEN state
255  */
256 static void
257 IpcpLayerUp(fp)
258 struct fsm *fp;
259 {
260   char tbuff[100];
261 
262 #ifdef VERBOSE
263   fprintf(stderr, "%s: LayerUp(%d).\r\n", fp->name, fp->state);
264 #endif
265   Prompt(1);
266   LogPrintf(LOG_LCP, "%s: LayerUp.\n", fp->name);
267   sprintf(tbuff, "myaddr = %s ", inet_ntoa(IpcpInfo.want_ipaddr));
268   LogPrintf(LOG_LCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(IpcpInfo.his_ipaddr));
269   OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
270   OsLinkup();
271   IpcpStartReport();
272   StartIdleTimer();
273 }
274 
275 void
276 IpcpUp()
277 {
278   FsmUp(&IpcpFsm);
279   LogPrintf(LOG_LCP, "IPCP Up event!!\n");
280 }
281 
282 void
283 IpcpOpen()
284 {
285   FsmOpen(&IpcpFsm);
286 }
287 
288 static int
289 AcceptableAddr(prange, ipaddr)
290 struct in_range *prange;
291 struct in_addr ipaddr;
292 {
293 #ifdef DEBUG
294   logprintf("requested = %x ", htonl(ipaddr.s_addr));
295   logprintf("range = %x", htonl(prange->ipaddr.s_addr));
296   logprintf("/%x\n", htonl(prange->mask.s_addr));
297   logprintf("%x, %x\n", htonl(prange->ipaddr.s_addr & prange->mask.s_addr),
298     htonl(ipaddr.s_addr & prange->mask.s_addr));
299 #endif
300   return((prange->ipaddr.s_addr & prange->mask.s_addr) ==
301 	(ipaddr.s_addr & prange->mask.s_addr));
302 }
303 
304 static void
305 IpcpDecodeConfig(cp, plen, mode)
306 u_char *cp;
307 int plen;
308 int mode;
309 {
310   int type, length;
311   u_long *lp, compproto;
312   struct compreq *pcomp;
313   struct in_addr ipaddr, dstipaddr;
314   char tbuff[100];
315 
316   ackp = AckBuff;
317   nakp = NakBuff;
318   rejp = RejBuff;
319 
320   while (plen >= sizeof(struct fsmconfig)) {
321     if (plen < 0)
322       break;
323     type = *cp;
324     length = cp[1];
325     if (type <= TY_IPADDR)
326       sprintf(tbuff, " %s[%d] ", cftypes[type], length);
327     else
328       sprintf(tbuff, " ");
329 
330     switch (type) {
331     case TY_IPADDR:		/* RFC1332 */
332       lp = (u_long *)(cp + 2);
333       ipaddr.s_addr = *lp;
334       LogPrintf(LOG_LCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
335 
336       switch (mode) {
337       case MODE_REQ:
338 	if (!AcceptableAddr(&DefHisAddress, ipaddr)) {
339           /*
340            * If destination address is not acceptable, insist to use
341            * what we want to use.
342            */
343 	  bcopy(cp, nakp, 2);
344           bcopy(&IpcpInfo.his_ipaddr.s_addr, nakp+2, length);
345           nakp += length;
346           break;
347 
348 	}
349 	IpcpInfo.his_ipaddr = ipaddr;
350 	bcopy(cp, ackp, length);
351 	ackp += length;
352 	break;
353       case MODE_NAK:
354 	if (AcceptableAddr(&DefMyAddress, ipaddr)) {
355           /*
356            * Use address suggested by peer.
357            */
358 	  sprintf(tbuff+50, "%s changing address: %s ", tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
359 	  LogPrintf(LOG_LCP, "%s --> %s\n", tbuff+50, inet_ntoa(ipaddr));
360 	  IpcpInfo.want_ipaddr = ipaddr;
361 	}
362 	break;
363       case MODE_REJ:
364 	IpcpInfo.his_reject |= (1 << type);
365 	break;
366       }
367       break;
368     case TY_COMPPROTO:
369       lp = (u_long *)(cp + 2);
370       compproto = htonl(*lp);
371       LogPrintf(LOG_LCP, "%s %08x\n", tbuff, compproto);
372 
373       switch (mode) {
374       case MODE_REQ:
375 	if (!Acceptable(ConfVjcomp)) {
376 	  bcopy(cp, rejp, length);
377 	  rejp += length;
378 	} else {
379 	  pcomp = (struct compreq *)(cp + 2);
380 	  switch (length) {
381 	  case 4:	/* RFC1172 */
382 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
383 	      logprintf("** Peer is speaking RFC1172 compression protocol **\n");
384 	      IpcpInfo.heis1172 = 1;
385 	      IpcpInfo.his_compproto = compproto;
386 	      bcopy(cp, ackp, length);
387 	      ackp += length;
388 	    } else {
389 	      bcopy(cp, nakp, 2);
390 	      pcomp->proto = htons(PROTO_VJCOMP);
391 	      bcopy(&pcomp, nakp + 2, 2);
392 	      nakp += length;
393 	    }
394 	    break;
395 	  case 6: 	/* RFC1332 */
396 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
397 	        && pcomp->slots < MAX_STATES && pcomp->slots > 2) {
398 	      IpcpInfo.his_compproto = compproto;
399 	      IpcpInfo.heis1172 = 0;
400 	      bcopy(cp, ackp, length);
401 	      ackp += length;
402 	    } else {
403 	      bcopy(cp, nakp, 2);
404 	      pcomp->proto = htons(PROTO_VJCOMP);
405 	      pcomp->slots = MAX_STATES - 1;
406 	      pcomp->compcid = 0;
407 	      bcopy(&pcomp, nakp + 2, sizeof(pcomp));
408 	      nakp += length;
409 	    }
410 	    break;
411 	  default:
412 	    bcopy(cp, rejp, length);
413 	    rejp += length;
414 	    break;
415 	  }
416 	}
417 	break;
418       case MODE_NAK:
419 	LogPrintf(LOG_LCP, "%s changing compproto: %08x --> %08x\n",
420 	  tbuff, IpcpInfo.want_compproto, compproto);
421 	IpcpInfo.want_compproto = compproto;
422 	break;
423       case MODE_REJ:
424 	IpcpInfo.his_reject |= (1 << type);
425 	break;
426       }
427       break;
428     case TY_IPADDRS:	/* RFC1172 */
429       lp = (u_long *)(cp + 2);
430       ipaddr.s_addr = *lp;
431       lp = (u_long *)(cp + 6);
432       dstipaddr.s_addr = *lp;
433       LogPrintf(LOG_LCP, "%s %s, ", tbuff, inet_ntoa(ipaddr));
434       LogPrintf(LOG_LCP, "%s\n", inet_ntoa(dstipaddr));
435 
436       switch (mode) {
437       case MODE_REQ:
438 	IpcpInfo.his_ipaddr = ipaddr;
439 	IpcpInfo.want_ipaddr = dstipaddr;
440 	bcopy(cp, ackp, length);
441 	ackp += length;
442 	break;
443       case MODE_NAK:
444 	LogPrintf(LOG_LCP, "%s changing address: %s ",
445 	  tbuff, inet_ntoa(IpcpInfo.want_ipaddr));
446 	LogPrintf(LOG_LCP, "--> %s\n", inet_ntoa(ipaddr));
447 	IpcpInfo.want_ipaddr = ipaddr;
448 	IpcpInfo.his_ipaddr = dstipaddr;
449 	break;
450       case MODE_REJ:
451 	IpcpInfo.his_reject |= (1 << type);
452 	break;
453       }
454       break;
455     default:
456       IpcpInfo.my_reject |= (1 << type);
457       bcopy(cp, rejp, length);
458       rejp += length;
459       break;
460     }
461     plen -= length;
462     cp += length;
463   }
464 }
465 
466 void
467 IpcpInput(struct mbuf *bp)
468 {
469   FsmInput(&IpcpFsm, bp);
470 }
471