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