Commented out the ld -x -r lines and put NOPIC wrappers around the
[unix-history] / libexec / pppd / ipcp.c
CommitLineData
2a905848
RG
1/*
2 * ipcp.c - PPP IP Control Protocol.
3 *
4 * Copyright (c) 1989 Carnegie Mellon University.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by Carnegie Mellon University. The name of the
13 * University may not be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20/*
21 * TODO:
22 * Fix IP address negotiation (wantoptions or hisoptions).
23 * Don't set zero IP addresses.
24 * Send NAKs for unsent CIs.
25 * VJ compression.
26 */
27
28#include <stdio.h>
29#include <syslog.h>
30#include <sys/ioctl.h>
31#include <sys/types.h>
32#include <sys/socket.h>
33#include <sys/time.h>
34
35#include <net/if.h>
36#include <net/route.h>
37#include <netinet/in.h>
38
39#include <string.h>
40
41#ifndef BSD
42#ifndef sun
43#define BSD 44
44#endif
45#endif /*BSD*/
46
47#ifdef STREAMS
48#include <sys/stream.h>
49#include "ppp_str.h"
50#endif
51
52#include "pppd.h"
53#include <net/if_ppp.h>
54
55#include <net/ppp.h>
56#include "fsm.h"
57#include "ipcp.h"
58
59
60/* global vars */
61ipcp_options ipcp_wantoptions[NPPP]; /* Options that we want to request */
62ipcp_options ipcp_gotoptions[NPPP]; /* Options that peer ack'd */
63ipcp_options ipcp_allowoptions[NPPP]; /* Options that we allow peer to
64 request */
65ipcp_options ipcp_hisoptions[NPPP]; /* Options that we ack'd */
66
67/* local vars */
68
69/*
70 * VJ compression protocol mode for negotiation. See ipcp.h for a
71 * description of each mode.
72 */
73static int vj_mode = IPCP_VJMODE_RFC1332;
74
75static int vj_opt_len = 6; /* holds length in octets for valid vj */
76 /* compression frame depending on mode */
77
78static int vj_opt_val = IPCP_VJ_COMP;
79 /* compression negotiation frames */
80 /* depending on vj_mode */
81
82static void ipcp_resetci __ARGS((fsm *)); /* Reset our Configuration Information */
83static int ipcp_cilen __ARGS((fsm *)); /* Return length of our CI */
84static void ipcp_addci __ARGS((fsm *, u_char *)); /* Add our CIs */
85static int ipcp_ackci __ARGS((fsm *, u_char *, int)); /* Ack some CIs */
86static void ipcp_nakci __ARGS((fsm *, u_char *, int)); /* Nak some CIs */
87static void ipcp_rejci __ARGS((fsm *, u_char *, int)); /* Reject some CIs */
88static u_char ipcp_reqci __ARGS((fsm *, u_char *, int *)); /* Check the requested CIs */
89static void ipcp_up __ARGS((fsm *)); /* We're UP */
90static void ipcp_down __ARGS((fsm *)); /* We're DOWN */
91
92
93static fsm ipcp_fsm[NPPP]; /* IPCP fsm structure */
94
95static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
96 ipcp_resetci, /* Reset our Configuration Information */
97 ipcp_cilen, /* Length of our Configuration Information */
98 ipcp_addci, /* Add our Configuration Information */
99 ipcp_ackci, /* ACK our Configuration Information */
100 ipcp_nakci, /* NAK our Configuration Information */
101 ipcp_rejci, /* Reject our Configuration Information */
102 ipcp_reqci, /* Request peer's Configuration Information */
103 ipcp_up, /* Called when fsm reaches OPEN state */
104 ipcp_down, /* Called when fsm leaves OPEN state */
105 NULL, /* Called when fsm reaches CLOSED state */
106 NULL, /* Called when Protocol-Reject received */
107 NULL /* Retransmission is necessary */
108};
109
110char *
111ip_ntoa(ipaddr)
112u_long ipaddr;
113{
114 static char b1[64], b2[64], w = 0;
115 char *b = (w++&1) ? b1 : b2;
116
117 ipaddr = ntohl(ipaddr);
118
119 sprintf(b, "%d.%d.%d.%d",
120 (u_char)(ipaddr >> 24),
121 (u_char)(ipaddr >> 16),
122 (u_char)(ipaddr >> 8),
123 (u_char)(ipaddr));
124 return b;
125}
126
127/*
128 * ipcp_init - Initialize IPCP.
129 */
130void
131 ipcp_init(unit)
132int unit;
133{
134 fsm *f = &ipcp_fsm[unit];
135 ipcp_options *wo = &ipcp_wantoptions[unit];
136 ipcp_options *ao = &ipcp_allowoptions[unit];
137
138 f->unit = unit;
139 f->protocol = IPCP;
140 f->timeouttime = DEFTIMEOUT;
141 f->maxconfreqtransmits = DEFMAXCONFIGREQS;
142 f->maxtermtransmits = DEFMAXTERMTRANSMITS;
143 f->maxnakloops = DEFMAXNAKLOOPS;
144 f->callbacks = &ipcp_callbacks;
145
146 wo->neg_addrs = 1;
147 wo->ouraddr = 0;
148 wo->hisaddr = 0;
149
150 wo->neg_vj = 1;
151 wo->maxslotindex = MAX_STATES - 1; /* really max index */
152 wo->cflag = 1;
153
154 /* max slots and slot-id compression are currently hardwired in */
155 /* ppp_if.c to 16 and 1, this needs to be changed (among other */
156 /* things) gmc */
157
158 ao->neg_addrs = 1; /* accept old style dual addr */
159 ao->neg_addr = 1; /* accept new style single addr */
160 ao->neg_vj = 1;
161 ao->maxslotindex = MAX_STATES - 1;
162 ao->cflag = 1;
163 fsm_init(&ipcp_fsm[unit]);
164}
165
166/*
167 * ipcp_vj_setmode - set option length and option value for vj
168 * compression negotiation frames depending on mode
169 */
170
171void
172 ipcp_vj_setmode(mode)
173int mode;
174{
175 vj_mode = mode;
176
177 switch (vj_mode) {
178
179 case IPCP_VJMODE_OLD: /* with wrong code (0x0037) */
180 vj_opt_len = 4;
181 vj_opt_val = IPCP_VJ_COMP_OLD;
182 break;
183
184 case IPCP_VJMODE_RFC1172: /* as per rfc1172 */
185 vj_opt_len = 4;
186 vj_opt_val = IPCP_VJ_COMP;
187 break;
188
189 case IPCP_VJMODE_RFC1332: /* draft mode vj compression */
190 vj_opt_len = 6; /* negotiation includes values for */
191 /* maxslot and slot number compression */
192 vj_opt_val = IPCP_VJ_COMP;
193 break;
194
195 default:
196 IPCPDEBUG((LOG_WARNING, "Unknown vj compression mode %d. Please report \
197this error.", vj_mode))
198 break;
199 }
200
201}
202/*
203 * ipcp_activeopen - Actively open IPCP.
204 */
205void
206 ipcp_activeopen(unit)
207int unit;
208{
209 fsm_activeopen(&ipcp_fsm[unit]);
210}
211
212
213/*
214 * ipcp_passiveopen - Passively open IPCP.
215 */
216void ipcp_passiveopen(unit)
217 int unit;
218{
219 fsm_passiveopen(&ipcp_fsm[unit]);
220}
221
222
223/*
224 * ipcp_close - Close IPCP.
225 */
226void
227 ipcp_close(unit)
228int unit;
229{
230 fsm_close(&ipcp_fsm[unit]);
231}
232
233
234/*
235 * ipcp_lowerup - The lower layer is up.
236 */
237void
238 ipcp_lowerup(unit)
239int unit;
240{
241 fsm_lowerup(&ipcp_fsm[unit]);
242}
243
244
245/*
246 * ipcp_lowerdown - The lower layer is down.
247 */
248void
249 ipcp_lowerdown(unit)
250int unit;
251{
252 fsm_lowerdown(&ipcp_fsm[unit]);
253}
254
255
256/*
257 * ipcp_input - Input IPCP packet.
258 */
259void
260 ipcp_input(unit, p, len)
261int unit;
262u_char *p;
263int len;
264{
265 fsm_input(&ipcp_fsm[unit], p, len);
266}
267
268
269/*
270 * ipcp_protrej - A Protocol-Reject was received for IPCP.
271 *
272 * Simply pretend that LCP went down.
273 */
274void
275 ipcp_protrej(unit)
276int unit;
277{
278 fsm_lowerdown(&ipcp_fsm[unit]);
279}
280
281
282/*
283 * ipcp_resetci - Reset our CI.
284 */
285static void
286 ipcp_resetci(f)
287fsm *f;
288{
289 ipcp_gotoptions[f->unit] = ipcp_wantoptions[f->unit];
290}
291
292
293/*
294 * ipcp_cilen - Return length of our CI.
295 */
296static int
297 ipcp_cilen(f)
298fsm *f;
299{
300 ipcp_options *go = &ipcp_gotoptions[f->unit];
301
302
303#define LENCISHORT(neg) (neg ? vj_opt_len : 0)
304
305#define LENCIADDRS(neg) (neg ? 10 : 0)
306
307#define LENCIADDR(neg) (neg ? 6 : 0)
308
309 return (LENCIADDRS(go->neg_addrs) +
310 LENCIADDR(go->neg_addr) +
311 LENCISHORT(go->neg_vj));
312}
313
314
315/*
316 * ipcp_addci - Add our desired CIs to a packet.
317 */
318static void
319 ipcp_addci(f, ucp)
320fsm *f;
321u_char *ucp;
322{
323 ipcp_options *go = &ipcp_gotoptions[f->unit];
324
325
326#define ADDCISHORT(opt, neg, val, maxslotindex, cflag) \
327 if (neg) { \
328 PUTCHAR(opt, ucp); \
329 PUTCHAR(vj_opt_len, ucp); \
330 PUTSHORT(val, ucp); \
331 if (vj_mode == IPCP_VJMODE_RFC1332) { \
332 PUTCHAR(maxslotindex, ucp); \
333 PUTCHAR(cflag, ucp); \
334 } \
335 }
336
337#define ADDCIADDRS(opt, neg, val1, val2) \
338 if (neg) { \
339 u_long l; \
340 PUTCHAR(opt, ucp); \
341 PUTCHAR(2 + 2 * sizeof (long), ucp); \
342 l = ntohl(val1); \
343 PUTLONG(l, ucp); \
344 l = ntohl(val2); \
345 PUTLONG(l, ucp); \
346 }
347
348#define ADDCIADDR(opt, neg, val) \
349 if (neg) { \
350 u_long l; \
351 PUTCHAR(opt, ucp); \
352 PUTCHAR(2 + sizeof (long), ucp); \
353 l = ntohl(val); \
354 PUTLONG(l, ucp); \
355 }
356
357 ADDCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
358
359 ADDCIADDR(CI_ADDR, go->neg_addr, go->ouraddr)
360
361 ADDCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val,
362 go->maxslotindex, go->cflag)
363}
364
365
366/*
367 * ipcp_ackci - Ack our CIs.
368 *
369 * Returns:
370 * 0 - Ack was bad.
371 * 1 - Ack was good.
372 */
373static int
374 ipcp_ackci(f, p, len)
375fsm *f;
376u_char *p;
377int len;
378{
379 ipcp_options *go = &ipcp_gotoptions[f->unit];
380 u_short cilen, citype, cishort;
381 u_long cilong;
382 u_char cimaxslotindex, cicflag;
383 /*
384 * CIs must be in exactly the same order that we sent...
385 * Check packet length and CI length at each step.
386 * If we find any deviations, then this packet is bad.
387 */
388#define ACKCISHORT(opt, neg, val, maxslotindex, cflag) \
389 if (neg) { \
390 if ((len -= vj_opt_len) < 0) \
391 goto bad; \
392 GETCHAR(citype, p); \
393 GETCHAR(cilen, p); \
394 if (cilen != vj_opt_len || \
395 citype != opt) \
396 goto bad; \
397 GETSHORT(cishort, p); \
398 if (cishort != val) \
399 goto bad; \
400 if (vj_mode == IPCP_VJMODE_RFC1332) { \
401 GETCHAR(cimaxslotindex, p); \
402 if (cimaxslotindex > maxslotindex) \
403 goto bad; \
404 GETCHAR(cicflag, p); \
405 if (cicflag != cflag) \
406 goto bad; \
407 } \
408 }
409
410#define ACKCIADDRS(opt, neg, val1, val2) \
411 if (neg) { \
412 u_long l; \
413 if ((len -= 2 + 2 * sizeof (long)) < 0) \
414 goto bad; \
415 GETCHAR(citype, p); \
416 GETCHAR(cilen, p); \
417 if (cilen != 2 + 2 * sizeof (long) || \
418 citype != opt) \
419 goto bad; \
420 GETLONG(l, p); \
421 cilong = htonl(l); \
422 if (val1) { \
423 if (val1 != cilong) \
424 goto bad; \
425 } \
426 else \
427 val1 = cilong; \
428 GETLONG(l, p); \
429 cilong = htonl(l); \
430 if (val2) { \
431 if (val2 != cilong) \
432 goto bad; \
433 } \
434 else \
435 val2 = cilong; \
436 }
437
438#define ACKCIADDR(opt, neg, val) \
439 if (neg) { \
440 u_long l; \
441 if ((len -= 2 + sizeof (long)) < 0) \
442 goto bad; \
443 GETCHAR(citype, p); \
444 GETCHAR(cilen, p); \
445 if (cilen != 2 + sizeof (long) || \
446 citype != opt) \
447 goto bad; \
448 GETLONG(l, p); \
449 cilong = htonl(l); \
450 if (val) { \
451 if (val != cilong) \
452 goto bad; \
453 } \
454 else \
455 val = cilong; \
456 }
457
458 ACKCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
459 ACKCIADDR(CI_ADDR, go->neg_addr, go->ouraddr)
460 ACKCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val, go->maxslotindex, go->cflag)
461 /*
462 * If there are any remaining CIs, then this packet is bad.
463 */
464 if (len != 0)
465 goto bad;
466 return (1);
467
468bad:
469 IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!"));
470
471 if (vj_mode == IPCP_VJMODE_RFC1332 )
472 IPCPDEBUG((LOG_INFO, "ipcp_ackci: citype %d, cilen %l",
473 citype, cilen));
474
475 if (citype == CI_COMPRESSTYPE) {
476 IPCPDEBUG((LOG_INFO, "ipcp_ackci: compress_type %d", cishort));
477 if (vj_mode == IPCP_VJMODE_RFC1332)
478 IPCPDEBUG((LOG_INFO, ", maxslotindex %d, cflag %d",
479 cishort, cimaxslotindex, cicflag));
480 }
481 return (0);
482}
483
484/*
485 * ipcp_nakci - NAK some of our CIs.
486 *
487 * Returns:
488 * 0 - Nak was bad.
489 * 1 - Nak was good.
490 */
491static void
492 ipcp_nakci(f, p, len)
493fsm *f;
494u_char *p;
495int len;
496{
497 ipcp_options *go = &ipcp_gotoptions[f->unit];
498 u_char cimaxslotindex, cicflag;
499 u_short cishort;
500 u_long ciaddr1, ciaddr2;
501
502 /*
503 * Any Nak'd CIs must be in exactly the same order that we sent.
504 * Check packet length and CI length at each step.
505 * If we find any deviations, then this packet is bad.
506 */
507#define NAKCISHORT(opt, neg, code) \
508 if (neg && \
509 len >= vj_opt_len && \
510 p[1] == vj_opt_len && \
511 p[0] == opt) { \
512 len -= vj_opt_len; \
513 INCPTR(2, p); \
514 GETSHORT(cishort, p); \
515 if (vj_mode == IPCP_VJMODE_RFC1332) { \
516 GETCHAR(cimaxslotindex, p); \
517 GETCHAR(cicflag, p); \
518 } \
519 code \
520 }
521
522#define NAKCIADDRS(opt, neg, code) \
523 if (neg && \
524 len >= 2 + 2 * sizeof (long) && \
525 p[1] == 2 + 2 * sizeof (long) && \
526 p[0] == opt) { \
527 u_long l; \
528 len -= 2 + 2 * sizeof (long); \
529 INCPTR(2, p); \
530 GETLONG(l, p); \
531 ciaddr1 = htonl(l); \
532 GETLONG(l, p); \
533 ciaddr2 = htonl(l); \
534 code \
535 }
536
537#define NAKCIADDR(opt, neg, code) \
538 if (neg && \
539 len >= 2 + sizeof (long) && \
540 p[1] == 2 + sizeof (long) && \
541 p[0] == opt) { \
542 u_long l; \
543 len -= 2 + sizeof (long); \
544 INCPTR(2, p); \
545 GETLONG(l, p); \
546 ciaddr1 = htonl(l); \
547 code \
548 }
549
550 NAKCIADDRS(CI_ADDRS, go->neg_addrs,
551 if (!go->ouraddr) { /* Didn't know our address? */
552 syslog(LOG_INFO, "local IP address %s", ip_ntoa(ciaddr1));
553 go->ouraddr = ciaddr1;
554 }
555 if (ciaddr2) { /* Does he know his? */
556 go->hisaddr = ciaddr2;
557 syslog(LOG_INFO, "remote IP address %s", ip_ntoa(ciaddr2));
558 }
559 )
560
561 NAKCIADDR(CI_ADDR, go->neg_addr,
562 logf(LOG_INFO, "acquired IP address %s", ip_ntoa(ciaddr1));
563 if (!go->ouraddr) { /* Didn't know our address? */
564 go->ouraddr = ciaddr1;
565 syslog(LOG_INFO, "remote IP address %s", ip_ntoa(ciaddr1));
566 }
567 )
568
569 NAKCISHORT(CI_COMPRESSTYPE, go->neg_vj,
570 if (cishort != vj_opt_val)
571 goto bad;
572 go->maxslotindex = cimaxslotindex; /* this is what it */
573 go->cflag = cicflag; /* wants */
574
575 )
576 /*
577 * If there are any remaining CIs, then this packet is bad.
578 */
579 if (len == 0)
580 return;
581bad:
582 IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!"));
583}
584
585
586/*
587 * ipcp_rejci - Reject some of our CIs.
588 */
589static void
590 ipcp_rejci(f, p, len)
591fsm *f;
592u_char *p;
593int len;
594{
595 ipcp_options *go = &ipcp_gotoptions[f->unit];
596 u_char cimaxslotindex, ciflag;
597 u_short cishort;
598 u_long cilong;
599
600 /*
601 * Any Rejected CIs must be in exactly the same order that we sent.
602 * Check packet length and CI length at each step.
603 * If we find any deviations, then this packet is bad.
604 */
605#define REJCISHORT(opt, neg, val, maxslot, cflag) \
606 if (neg && \
607 len >= vj_opt_len && \
608 p[1] == vj_opt_len && \
609 p[0] == opt) { \
610 len -= vj_opt_len; \
611 INCPTR(2, p); \
612 GETSHORT(cishort, p); \
613 /* Check rejected value. */ \
614 if (cishort != val) \
615 goto bad; \
616 if (vj_mode == IPCP_VJMODE_RFC1332) { \
617 GETCHAR(cimaxslotindex, p); \
618 if (cimaxslotindex != maxslot) \
619 goto bad; \
620 GETCHAR(ciflag, p); \
621 if (ciflag != cflag) \
622 goto bad; \
623 } \
624 neg = 0; \
625 }
626
627#define REJCIADDRS(opt, neg, val1, val2) \
628 if (neg && \
629 len >= 2 + 2 * sizeof (long) && \
630 p[1] == 2 + 2 * sizeof (long) && \
631 p[0] == opt) { \
632 u_long l; \
633 len -= 2 + 2 * sizeof (long); \
634 INCPTR(2, p); \
635 GETLONG(l, p); \
636 cilong = htonl(l); \
637 /* Check rejected value. */ \
638 if (cilong != val2) \
639 goto bad; \
640 GETLONG(l, p); \
641 cilong = htonl(l); \
642 /* Check rejected value. */ \
643 if (cilong != val1) \
644 goto bad; \
645 neg = 0; \
646 }
647
648#define REJCIADDR(opt, neg, val) \
649 if (neg && \
650 len >= 2 + sizeof (long) && \
651 p[1] == 2 + sizeof (long) && \
652 p[0] == opt) { \
653 u_long l; \
654 len -= 2 + sizeof (long); \
655 INCPTR(2, p); \
656 GETLONG(l, p); \
657 cilong = htonl(l); \
658 /* Check rejected value. */ \
659 if (cilong != val) \
660 goto bad; \
661 neg = 0; \
662 }
663
664 REJCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
665
666 REJCIADDR(CI_ADDR, go->neg_addr, go->ouraddr)
667
668 REJCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val, go->maxslotindex, go->cflag)
669
670 /*
671 * If there are any remaining CIs, then this packet is bad.
672 */
673 if (len == 0)
674 return;
675
676bad:
677 IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!"));
678}
679
680
681/*
682 * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
683 *
684 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
685 * appropriately.
686 */
687static u_char
688 ipcp_reqci(f, inp, len)
689fsm *f;
690u_char *inp; /* Requested CIs */
691int *len; /* Length of requested CIs */
692{
693 ipcp_options *wo = &ipcp_wantoptions[f->unit];
694 ipcp_options *ho = &ipcp_hisoptions[f->unit];
695 ipcp_options *ao = &ipcp_allowoptions[f->unit];
696 ipcp_options *go = &ipcp_gotoptions[f->unit];
697 u_char *cip; /* Pointer to Current CI */
698 u_short cilen, citype; /* Parsed len, type */
699 u_short cishort; /* Parsed short value */
700 u_long tl, ciaddr1, ciaddr2; /* Parsed address values */
701 int rc = CONFACK; /* Final packet return code */
702 int orc; /* Individual option return code */
703 u_char *p = inp; /* Pointer to next char to parse */
704 u_char *ucp = inp; /* Pointer to current output char */
705 int l = *len; /* Length left */
706 u_char maxslotindex, cflag;
707
708 /*
709 * Reset all his options.
710 */
711 ho->neg_addrs = 0;
712 ho->neg_vj = 0;
713 ho->maxslotindex = 0;
714 ho->cflag = 0;
715
716 /*
717 * Process all his options.
718 */
719 while (l) {
720 orc = CONFACK; /* Assume success */
721 cip = p; /* Remember begining of CI */
722 if (l < 2 || /* Not enough data for CI header or */
723 p[1] < 2 || /* CI length too small or */
724 p[1] > l) { /* CI length too big? */
725 IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!"));
726 orc = CONFREJ; /* Reject bad CI */
727 cilen = l; /* Reject till end of packet */
728 l = 0; /* Don't loop again */
729 goto endswitch;
730 }
731 GETCHAR(citype, p); /* Parse CI type */
732 GETCHAR(cilen, p); /* Parse CI length */
733 l -= cilen; /* Adjust remaining length */
734 cilen -= 2; /* Adjust cilen to just data */
735
736 switch (citype) { /* Check CI type */
737 case CI_ADDRS:
738 logf(LOG_INFO, "ipcp: received ADDRS ");
739 if (!ao->neg_addrs ||
740 cilen != 2 * sizeof (long))
741 { /* Check CI length */
742 INCPTR(cilen, p); /* Skip rest of CI */
743 orc = CONFREJ; /* Reject CI */
744 break;
745 }
746
747 /*
748 * If he has no address, or if we both have his address but
749 * disagree about it, then NAK it with our idea.
750 * In particular, if we don't know his address, but he does,
751 * then accept it.
752 */
753 GETLONG(tl, p); /* Parse source address (his) */
754 ciaddr1 = htonl(tl);
755 if (!ciaddr1 ||
756 (wo->neg_addrs && wo->hisaddr && ciaddr1 != wo->hisaddr))
757 {
758 orc = CONFNAK;
759 DECPTR(sizeof (long), p);
760 tl = wo->neg_addrs ? ntohl(wo->hisaddr) : 0;
761 PUTLONG(tl, p);
762 }
763
764 /*
765 * If he doesn't know our address, or if we both have our address
766 * but disagree about it, then NAK it with our idea.
767 */
768 GETLONG(tl, p); /* Parse desination address (ours) */
769 ciaddr2 = htonl(tl);
770 logf(LOG_INFO, "(%s:%s)", ip_ntoa(ciaddr1), ip_ntoa(ciaddr2));
771 if (!ciaddr2 ||
772 (wo->neg_addrs && wo->ouraddr && ciaddr2 != wo->ouraddr))
773 {
774 orc = CONFNAK;
775 DECPTR(sizeof (long), p);
776 tl = ntohl(wo->ouraddr);
777 PUTLONG(tl, p);
778 }
779 if (orc == CONFNAK)
780 break;
781
782 /* XXX ho or go? */
783 ho->neg_addrs = 1;
784 ho->hisaddr = ciaddr1;
785 ho->ouraddr = ciaddr2;
786 break;
787
788 case CI_ADDR:
789 logf(LOG_INFO, "ipcp: received ADDR ");
790 go->got_addr = 1;
791 go->neg_addrs = 0;
792 go->neg_addr = 1;
793
794 if (!ao->neg_addr ||
795 cilen != sizeof (long)) { /* Check CI length */
796 INCPTR(cilen, p); /* Skip rest of CI */
797 orc = CONFREJ; /* Reject CI */
798 break;
799 }
800
801 /*
802 * If he has no address, or if we both have his address but
803 * disagree about it, then NAK it with our idea.
804 * In particular, if we don't know his address, but he does,
805 * then accept it.
806 */
807 GETLONG(tl, p); /* Parse source address (his) */
808 ciaddr1 = htonl(tl);
809 logf(LOG_INFO, "(%s)", ip_ntoa(ciaddr1));
810 if (!ciaddr1 ||
811 (wo->neg_addr && wo->hisaddr && ciaddr1 != wo->hisaddr)) {
812 orc = CONFNAK;
813 DECPTR(sizeof (long), p);
814 tl = wo->neg_addr ? ntohl(wo->hisaddr) : 0;
815 PUTLONG(tl, p);
816 }
817
818 if (orc == CONFNAK)
819 break;
820
821 /* XXX ho or go? */
822 ho->neg_addr = 1;
823 ho->hisaddr = ciaddr1;
824 break;
825
826 case CI_COMPRESSTYPE:
827 logf(LOG_INFO, "ipcp: received COMPRESSTYPE ");
828 if (!ao->neg_vj ||
829 cilen != (vj_opt_len - 2)) {
830 INCPTR(cilen, p);
831 orc = CONFREJ;
832 break;
833 }
834 GETSHORT(cishort, p);
835 logf(LOG_INFO, "(%d)", cishort);
836
837 /*
838 * Compresstype must be vj_opt_val.
839 */
840 if (cishort != vj_opt_val) {
841 DECPTR(sizeof (short), p);
842 orc = CONFNAK;
843 PUTSHORT(vj_opt_val, p);
844 break;
845 }
846 ho->neg_vj = 1;
847 if (vj_mode == IPCP_VJMODE_RFC1332) {
848 GETCHAR(maxslotindex, p);
849 if (maxslotindex > wo->maxslotindex) {
850 DECPTR(1, p);
851 orc = CONFNAK;
852 PUTCHAR(wo->maxslotindex, p);
853 break;
854 }
855 ho->maxslotindex = maxslotindex;
856
857 GETCHAR(cflag, p);
858 if (cflag != wo->cflag) {
859 DECPTR(1, p);
860 orc = CONFNAK;
861 PUTCHAR(wo->cflag, p);
862 break;
863 }
864 ho->cflag = wo->cflag;
865 }
866 break;
867
868 default:
869 INCPTR(cilen, p);
870 orc = CONFREJ;
871 break;
872 }
873 cilen += 2; /* Adjust cilen whole CI */
874
875endswitch:
876 logf(LOG_INFO, " (%s)\n",
877 orc == CONFACK ? "ACK" : (orc == CONFNAK ? "NAK" : "Reject"));
878
879 if (orc == CONFACK && /* Good CI */
880 rc != CONFACK) /* but prior CI wasnt? */
881 continue; /* Don't send this one */
882
883 if (orc == CONFNAK) { /* Nak this CI? */
884 if (rc == CONFREJ) /* Rejecting prior CI? */
885 continue; /* Don't send this one */
886 if (rc == CONFACK) { /* Ack'd all prior CIs? */
887 rc = CONFNAK; /* Not anymore... */
888 ucp = inp; /* Backup */
889 }
890 }
891
892 if (orc == CONFREJ && /* Reject this CI */
893 rc != CONFREJ) { /* but no prior ones? */
894 rc = CONFREJ;
895 ucp = inp; /* Backup */
896 }
897
898 /* Need to move CI? */
899 if (ucp != cip)
900 /* Move it */
901 memcpy(ucp, cip, (size_t)cilen);
902
903 /* Update output pointer */
904 INCPTR(cilen, ucp);
905 }
906
907 /*
908 * XXX If we wanted to send additional NAKs (for unsent CIs), the
909 * code would go here. This must be done with care since it might
910 * require a longer packet than we received.
911 */
912
913 *len = ucp - inp; /* Compute output length */
914
915 syslog(LOG_INFO, "ipcp: returning Configure-%s",
916 rc == CONFACK ? "ACK" :
917 rc == CONFNAK ? "NAK" : "Reject");
918
919 return (rc); /* Return final code */
920}
921
922
923/*
924 * ipcp_up - IPCP has come UP.
925 */
926static void
927 ipcp_up(f)
928fsm *f;
929{
930 u_long mask;
931
932 syslog(LOG_INFO, "ipcp: up");
933
934 if (ipcp_hisoptions[f->unit].hisaddr == 0)
935 ipcp_hisoptions[f->unit].hisaddr = ipcp_wantoptions[f->unit].hisaddr;
936
937 syslog(LOG_INFO, "local IP address %s",
938 ip_ntoa(ipcp_gotoptions[f->unit].ouraddr));
939 syslog(LOG_INFO, "remote IP address %s",
940 ip_ntoa(ipcp_hisoptions[f->unit].hisaddr));
941
942 SIFADDR(f->unit, ipcp_gotoptions[f->unit].ouraddr,
943 ipcp_hisoptions[f->unit].hisaddr);
944
945 /* set new netmask if specified */
946 mask = GetMask(ipcp_gotoptions[f->unit].ouraddr);
947 if (mask)
948 SIFMASK(f->unit, mask);
949
950 /* set tcp compression */
951 SIFVJCOMP(f->unit, ipcp_hisoptions[f->unit].neg_vj);
952}
953
954
955/*
956 * ipcp_down - IPCP has gone DOWN.
957 *
958 * Alert other protocols.
959 */
960static void
961 ipcp_down(f)
962fsm *f;
963{
964 syslog(LOG_INFO, "ipcp: down");
965
966 CIFADDR(f->unit, ipcp_gotoptions[f->unit].ouraddr,
967 ipcp_hisoptions[f->unit].hisaddr);
968}