]> git.ozlabs.org Git - ppp.git/blob - pppd/ipxcp.c
prototypes always (remove __P)
[ppp.git] / pppd / ipxcp.c
1 /*
2  * ipxcp.c - PPP IPX 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 #ifdef IPX_CHANGE
21 #ifndef lint
22 static char rcsid[] = "$Id: ipxcp.c,v 1.3 1996/09/14 05:15:20 paulus Exp $";
23 #endif
24
25 /*
26  * TODO:
27  */
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <syslog.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35
36 #include "pppd.h"
37 #include "fsm.h"
38 #include "ipxcp.h"
39 #include "pathnames.h"
40
41 /* global vars */
42 ipxcp_options ipxcp_wantoptions[NUM_PPP];       /* Options that we want to request */
43 ipxcp_options ipxcp_gotoptions[NUM_PPP];        /* Options that peer ack'd */
44 ipxcp_options ipxcp_allowoptions[NUM_PPP];      /* Options we allow peer to request */
45 ipxcp_options ipxcp_hisoptions[NUM_PPP];        /* Options that we ack'd */
46
47 #define wo (&ipxcp_wantoptions[0])
48 #define ao (&ipxcp_allowoptions[0])
49 #define go (&ipxcp_gotoptions[0])
50 #define ho (&ipxcp_hisoptions[0])
51
52 /*
53  * Callbacks for fsm code.  (CI = Configuration Information)
54  */
55 static void ipxcp_resetci __P((fsm *)); /* Reset our CI */
56 static int  ipxcp_cilen __P((fsm *));           /* Return length of our CI */
57 static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
58 static int  ipxcp_ackci __P((fsm *, u_char *, int));    /* Peer ack'd our CI */
59 static int  ipxcp_nakci __P((fsm *, u_char *, int));    /* Peer nak'd our CI */
60 static int  ipxcp_rejci __P((fsm *, u_char *, int));    /* Peer rej'd our CI */
61 static int  ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
62 static void ipxcp_up __P((fsm *));              /* We're UP */
63 static void ipxcp_down __P((fsm *));            /* We're DOWN */
64 static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */
65
66 fsm ipxcp_fsm[NUM_PPP];         /* IPXCP fsm structure */
67
68 static fsm_callbacks ipxcp_callbacks = { /* IPXCP callback routines */
69     ipxcp_resetci,              /* Reset our Configuration Information */
70     ipxcp_cilen,                /* Length of our Configuration Information */
71     ipxcp_addci,                /* Add our Configuration Information */
72     ipxcp_ackci,                /* ACK our Configuration Information */
73     ipxcp_nakci,                /* NAK our Configuration Information */
74     ipxcp_rejci,                /* Reject our Configuration Information */
75     ipxcp_reqci,                /* Request peer's Configuration Information */
76     ipxcp_up,                   /* Called when fsm reaches OPENED state */
77     ipxcp_down,                 /* Called when fsm leaves OPENED state */
78     NULL,                       /* Called when we want the lower layer up */
79     NULL,                       /* Called when we want the lower layer down */
80     NULL,                       /* Called when Protocol-Reject received */
81     NULL,                       /* Retransmission is necessary */
82     NULL,                       /* Called to handle protocol-specific codes */
83     "IPXCP"                     /* String name of protocol */
84 };
85
86 /*
87  * Protocol entry points.
88  */
89
90 static void ipxcp_init __P((int));
91 static void ipxcp_open __P((int));
92 static void ipxcp_close __P((int, char *));
93 static void ipxcp_lowerup __P((int));
94 static void ipxcp_lowerdown __P((int));
95 static void ipxcp_input __P((int, u_char *, int));
96 static void ipxcp_protrej __P((int));
97 static int  ipxcp_printpkt __P((u_char *, int,
98                                 void (*) __P((void *, char *, ...)), void *));
99
100 struct protent ipxcp_protent = {
101     PPP_IPXCP,
102     ipxcp_init,
103     ipxcp_input,
104     ipxcp_protrej,
105     ipxcp_lowerup,
106     ipxcp_lowerdown,
107     ipxcp_open,
108     ipxcp_close,
109     ipxcp_printpkt,
110     NULL,
111     0,
112     "IPXCP",
113     NULL,
114     NULL,
115     NULL
116 };
117
118
119 /*
120  * Lengths of configuration options.
121  */
122
123 #define CILEN_VOID      2
124 #define CILEN_COMPLETE  2       /* length of complete option */
125 #define CILEN_NETN      6       /* network number length option */
126 #define CILEN_NODEN     8       /* node number length option */
127 #define CILEN_PROTOCOL  4       /* Minimum length of routing protocol */
128 #define CILEN_NAME      3       /* Minimum length of router name */
129 #define CILEN_COMPRESS  4       /* Minimum length of compression protocol */
130
131 #define CODENAME(x)     ((x) == CONFACK ? "ACK" : \
132                          (x) == CONFNAK ? "NAK" : "REJ")
133
134 /* Used in printing the node number */
135 #define NODE(base) base[0], base[1], base[2], base[3], base[4], base[5]
136
137 /* Used to generate the proper bit mask */
138 #define BIT(num)   (1 << (num))
139
140 /*
141  * Make a string representation of a network IP address.
142  */
143
144 char *
145 ipx_ntoa(ipxaddr)
146 u_int32_t ipxaddr;
147 {
148     static char b[64];
149     sprintf(b, "%lx", ipxaddr);
150     return b;
151 }
152
153
154 /*
155  * ipxcp_init - Initialize IPXCP.
156  */
157 static void
158 ipxcp_init(unit)
159     int unit;
160 {
161     fsm *f = &ipxcp_fsm[unit];
162
163     f->unit      = unit;
164     f->protocol  = PPP_IPXCP;
165     f->callbacks = &ipxcp_callbacks;
166     fsm_init(&ipxcp_fsm[unit]);
167
168     memset (wo->name,     0, sizeof (wo->name));
169     memset (wo->our_node, 0, sizeof (wo->our_node));
170     memset (wo->his_node, 0, sizeof (wo->his_node));
171
172     wo->neg_nn         = 1;
173     wo->neg_complete   = 1;
174     wo->network        = 0;
175
176     ao->neg_node       = 1;
177     ao->neg_nn         = 1;
178     ao->neg_name       = 1;
179     ao->neg_complete   = 1;
180     ao->neg_router     = 1;
181
182     ao->accept_local   = 0;
183     ao->accept_remote  = 0;
184     ao->accept_network = 0;
185 }
186
187 /*
188  * Copy the node number
189  */
190
191 static void
192 copy_node (src, dst)
193 u_char *src, *dst;
194 {
195     memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node));
196 }
197
198 /*
199  * Compare node numbers
200  */
201
202 static int
203 compare_node (src, dst)
204 u_char *src, *dst;
205 {
206     return memcmp (dst, src, sizeof (ipxcp_wantoptions[0].our_node)) == 0;
207 }
208
209 /*
210  * Is the node number zero?
211  */
212
213 static int
214 zero_node (node)
215 u_char *node;
216 {
217     int indx;
218     for (indx = 0; indx < sizeof (ipxcp_wantoptions[0].our_node); ++indx)
219         if (node [indx] != 0)
220             return 0;
221     return 1;
222 }
223
224 /*
225  * Increment the node number
226  */
227
228 static void
229 inc_node (node)
230 u_char *node;
231 {
232     u_char   *outp;
233     u_int32_t magic_num;
234
235     outp      = node;
236     magic_num = magic();
237     *outp++   = '\0';
238     *outp++   = '\0';
239     PUTLONG (magic_num, outp);
240 }
241
242 /*
243  * ipxcp_open - IPXCP is allowed to come up.
244  */
245 static void
246 ipxcp_open(unit)
247     int unit;
248 {
249     fsm_open(&ipxcp_fsm[unit]);
250 }
251
252 /*
253  * ipxcp_close - Take IPXCP down.
254  */
255 static void
256 ipxcp_close(unit, reason)
257     int unit;
258     char *reason;
259 {
260     fsm_close(&ipxcp_fsm[unit], reason);
261 }
262
263
264 /*
265  * ipxcp_lowerup - The lower layer is up.
266  */
267 static void
268 ipxcp_lowerup(unit)
269     int unit;
270 {
271     fsm_lowerup(&ipxcp_fsm[unit]);
272 }
273
274
275 /*
276  * ipxcp_lowerdown - The lower layer is down.
277  */
278 static void
279 ipxcp_lowerdown(unit)
280     int unit;
281 {
282     fsm_lowerdown(&ipxcp_fsm[unit]);
283 }
284
285
286 /*
287  * ipxcp_input - Input IPXCP packet.
288  */
289 static void
290 ipxcp_input(unit, p, len)
291     int unit;
292     u_char *p;
293     int len;
294 {
295     fsm_input(&ipxcp_fsm[unit], p, len);
296 }
297
298
299 /*
300  * ipxcp_protrej - A Protocol-Reject was received for IPXCP.
301  *
302  * Pretend the lower layer went down, so we shut up.
303  */
304 static void
305 ipxcp_protrej(unit)
306     int unit;
307 {
308     fsm_lowerdown(&ipxcp_fsm[unit]);
309 }
310
311
312 /*
313  * ipxcp_resetci - Reset our CI.
314  */
315 static void
316 ipxcp_resetci(f)
317     fsm *f;
318 {
319     u_int32_t network;
320     int unit = f->unit;
321
322     wo->req_node = wo->neg_node && ao->neg_node;
323     wo->req_nn   = wo->neg_nn   && ao->neg_nn;
324
325     if (wo->our_network == 0) {
326         wo->neg_node       = 1;
327         ao->accept_network = 1;
328     }
329 /*
330  * If our node number is zero then change it.
331  */
332     if (zero_node (wo->our_node)) {
333         inc_node (wo->our_node);
334         ao->accept_local = 1;
335         wo->neg_node     = 1;
336     }
337 /*
338  * If his node number is zero then change it.
339  */
340     if (zero_node (wo->his_node)) {
341         inc_node (wo->his_node);
342         ao->accept_remote = 1;
343     }
344 /*
345  * Unless router protocol is suppressed then assume that we can do RIP.
346  */
347     if (! (wo->router & BIT(0)))
348         wo->router |= BIT(2);
349 /*
350  * Router protocol is only negotiated if requested. Others force the
351  * negotiation.
352  */
353     if (wo->router & (BIT(2) | BIT(4)))
354         wo->neg_router = 1;
355 /*
356  * Start with these default values
357  */
358     *go = *wo;
359 }
360
361 /*
362  * ipxcp_cilen - Return length of our CI.
363  */
364 static int
365 ipxcp_cilen(f)
366     fsm *f;
367 {
368     int unit = f->unit;
369     int len;
370
371     len  = go->neg_nn       ? CILEN_NETN     : 0;
372     len += go->neg_node     ? CILEN_NODEN    : 0;
373     len += go->neg_name     ? CILEN_NAME + strlen (go->name) - 1 : 0;
374     len += go->neg_complete ? CILEN_COMPLETE : 0;
375 /*
376  * Router protocol 0 is mutually exclusive with the others.
377  */
378     if (go->neg_router) {
379         if (go->router & BIT(0))
380             len += CILEN_PROTOCOL;
381         else {
382             if (go->router & BIT(2))
383                 len += CILEN_PROTOCOL;
384             if (go->router & BIT(4))
385                 len += CILEN_PROTOCOL;
386         }
387     }
388
389     return (len);
390 }
391
392
393 /*
394  * ipxcp_addci - Add our desired CIs to a packet.
395  */
396 static void
397 ipxcp_addci(f, ucp, lenp)
398     fsm *f;
399     u_char *ucp;
400     int *lenp;
401 {
402     int len = *lenp;
403     int unit = f->unit;
404 /*
405  * Add the options to the record.
406  */
407     if (go->neg_nn) {
408         PUTCHAR (IPX_NETWORK_NUMBER, ucp);
409         PUTCHAR (CILEN_NETN, ucp);
410         PUTLONG (go->our_network, ucp);
411     }
412
413     if (go->neg_node) {
414         int indx;
415         PUTCHAR (IPX_NODE_NUMBER, ucp);
416         PUTCHAR (CILEN_NODEN, ucp);
417         for (indx = 0; indx < sizeof (go->our_node); ++indx)
418             PUTCHAR (go->our_node[indx], ucp);
419     }
420
421     if (go->neg_name) {
422         int cilen = strlen (go->name);
423         int indx;
424         PUTCHAR (IPX_ROUTER_NAME, ucp);
425         PUTCHAR (CILEN_NAME + cilen - 1, ucp);
426         for (indx = 0; indx < cilen; ++indx)
427             PUTCHAR (go->name [indx], ucp);
428     }
429
430     if (go->neg_router && (go->router & (BIT(0) | BIT(2) | BIT(4)))) {
431         if (go->router & BIT(0)) {
432             PUTCHAR  (IPX_ROUTER_PROTOCOL, ucp);
433             PUTCHAR  (CILEN_PROTOCOL,      ucp);
434             PUTSHORT (0,                   ucp);
435         } else {
436             if (go->router & BIT(2)) {
437                 PUTCHAR  (IPX_ROUTER_PROTOCOL, ucp);
438                 PUTCHAR  (CILEN_PROTOCOL,      ucp);
439                 PUTSHORT (2,                   ucp);
440             }
441             
442             if (go->router & BIT(4)) {
443                 PUTCHAR  (IPX_ROUTER_PROTOCOL, ucp);
444                 PUTCHAR  (CILEN_PROTOCOL,      ucp);
445                 PUTSHORT (4,                   ucp);
446             }
447         }
448     }
449
450     if (go->neg_complete) {
451         PUTCHAR (IPX_COMPLETE,   ucp);
452         PUTCHAR (CILEN_COMPLETE, ucp);
453     }
454 }
455
456 /*
457  * ipxcp_ackci - Ack our CIs.
458  *
459  * Returns:
460  *      0 - Ack was bad.
461  *      1 - Ack was good.
462  */
463 static int
464 ipxcp_ackci(f, p, len)
465     fsm *f;
466     u_char *p;
467     int len;
468 {
469     int unit = f->unit;
470     u_short cilen, citype, cishort;
471     u_char cichar;
472     u_int32_t cilong;
473
474 #define ACKCIVOID(opt, neg) \
475     if (neg) { \
476         if ((len -= CILEN_VOID) < 0) \
477             break; \
478         GETCHAR(citype, p); \
479         GETCHAR(cilen, p); \
480         if (cilen != CILEN_VOID || \
481             citype != opt) \
482             break; \
483     }
484
485 #define ACKCICOMPLETE(opt,neg)  ACKCIVOID(opt, neg)
486
487 #define ACKCICHARS(opt, neg, val, cnt) \
488     if (neg) { \
489         int indx, count = cnt; \
490         len -= (count + 2); \
491         if (len < 0) \
492             break; \
493         GETCHAR(citype, p); \
494         GETCHAR(cilen, p); \
495         if (cilen != (count + 2) || \
496             citype != opt) \
497             break; \
498         for (indx = 0; indx < count; ++indx) {\
499             GETCHAR(cichar, p); \
500             if (cichar != ((u_char *) &val)[indx]) \
501                break; \
502         }\
503         if (indx != count) \
504             break; \
505     }
506
507 #define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val))
508 #define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val))
509
510 #define ACKCINETWORK(opt, neg, val) \
511     if (neg) { \
512         if ((len -= CILEN_NETN) < 0) \
513             break; \
514         GETCHAR(citype, p); \
515         GETCHAR(cilen, p); \
516         if (cilen != CILEN_NETN || \
517             citype != opt) \
518             break; \
519         GETLONG(cilong, p); \
520         if (cilong != val) \
521             break; \
522     }
523
524 #define ACKCIPROTO(opt, neg, val, bit) \
525     if (neg && (val & BIT(bit))) \
526       { \
527         if (len < 2) \
528             break; \
529         GETCHAR(citype, p); \
530         GETCHAR(cilen, p); \
531         if (cilen != CILEN_PROTOCOL || citype != opt) \
532             break; \
533         len -= cilen; \
534         if (len < 0) \
535             break; \
536         GETSHORT(cishort, p); \
537         if (cishort != (bit)) \
538             break; \
539       }
540 /*
541  * Process the ACK frame in the order in which the frame was assembled
542  */
543     do {
544         ACKCINETWORK  (IPX_NETWORK_NUMBER,  go->neg_nn,     go->our_network);
545         ACKCINODE     (IPX_NODE_NUMBER,     go->neg_node,   go->our_node);
546         ACKCINAME     (IPX_ROUTER_NAME,     go->neg_name,   go->name);
547         ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router, 0);
548         ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router, 2);
549         ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router, 4);
550         ACKCICOMPLETE (IPX_COMPLETE,        go->neg_complete);
551 /*
552  * This is the end of the record.
553  */
554         if (len == 0)
555             return (1);
556     } while (0);
557 /*
558  * The frame is invalid
559  */
560     IPXCPDEBUG((LOG_INFO, "ipxcp_ackci: received bad Ack!"));
561     return (0);
562 }
563
564 /*
565  * ipxcp_nakci - Peer has sent a NAK for some of our CIs.
566  * This should not modify any state if the Nak is bad
567  * or if IPXCP is in the OPENED state.
568  *
569  * Returns:
570  *      0 - Nak was bad.
571  *      1 - Nak was good.
572  */
573
574 static int
575 ipxcp_nakci(f, p, len)
576     fsm *f;
577     u_char *p;
578     int len;
579 {
580     int unit = f->unit;
581     u_char citype, cilen, *next;
582     u_short s;
583     u_int32_t l;
584     ipxcp_options no;           /* options we've seen Naks for */
585     ipxcp_options try;          /* options to request next time */
586
587     BZERO(&no, sizeof(no));
588     try = *go;
589
590     while (len > CILEN_VOID) {
591         GETCHAR (citype, p);
592         GETCHAR (cilen,  p);
593         len -= cilen;
594         if (len < 0)
595             goto bad;
596         next = &p [cilen - CILEN_VOID];
597
598         switch (citype) {
599         case IPX_NETWORK_NUMBER:
600             if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN))
601                 goto bad;
602             no.neg_nn = 1;
603
604             GETLONG(l, p);
605             IPXCPDEBUG((LOG_INFO, "local IP address %d", l));
606             if (l && ao->accept_network)
607                 try.our_network = l;
608             break;
609
610         case IPX_NODE_NUMBER:
611             if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN))
612                 goto bad;
613             no.neg_node = 1;
614
615             IPXCPDEBUG((LOG_INFO,
616                         "local node number %02X%02X%02X%02X%02X%02X",
617                         NODE(p)));
618
619             if (!zero_node (p) && ao->accept_local &&
620                 ! compare_node (p, ho->his_node))
621                 copy_node (p, try.our_node);
622             break;
623
624             /* These have never been sent. Ignore the NAK frame */
625         case IPX_COMPRESSION_PROTOCOL:
626             goto bad;
627
628         case IPX_ROUTER_PROTOCOL:
629             if (!go->neg_router || (cilen < CILEN_PROTOCOL))
630                 goto bad;
631
632             GETSHORT (s, p);
633             if ((s != 0) && (s != 2) && (s != 4))
634                 goto bad;
635
636             if (no.router & BIT(s))
637                 goto bad;
638
639             if (no.router == 0) /* Reset on first NAK only */
640                 try.router = 0;
641             no.router      |= BIT(s);
642             try.router     |= BIT(s);
643             try.neg_router  = 1;
644
645             IPXCPDEBUG((LOG_INFO, "Router protocol number %d", s));
646             break;
647
648             /* These, according to the RFC, must never be NAKed. */
649         case IPX_ROUTER_NAME:
650         case IPX_COMPLETE:
651             goto bad;
652
653             /* These are for options which we have not seen. */
654         default:
655             break;
656         }
657         p = next;
658     }
659
660     /* If there is still anything left, this packet is bad. */
661     if (len != 0)
662         goto bad;
663
664     /*
665      * Do not permit the peer to force a router protocol which we do not
666      * support.
667      */
668     try.router &= go->router;
669     if (try.router == 0 && go->router != 0) {
670         try.neg_router = 1;
671         try.router     = BIT(0);
672     }
673     
674     /*
675      * OK, the Nak is good.  Now we can update state.
676      */
677     if (f->state != OPENED)
678         *go = try;
679
680     return 1;
681
682 bad:
683     IPXCPDEBUG((LOG_INFO, "ipxcp_nakci: received bad Nak!"));
684     return 0;
685 }
686
687 /*
688  * ipxcp_rejci - Reject some of our CIs.
689  */
690 static int
691 ipxcp_rejci(f, p, len)
692     fsm *f;
693     u_char *p;
694     int len;
695 {
696     int unit = f->unit;
697     u_short cilen, citype, cishort;
698     u_char cichar;
699     u_int32_t cilong;
700     ipxcp_options try;          /* options to request next time */
701
702 #define REJCINETWORK(opt, neg, val) \
703     if (neg) { \
704         neg = 0; \
705         if ((len -= CILEN_NETN) < 0) \
706             break; \
707         GETCHAR(citype, p); \
708         GETCHAR(cilen, p); \
709         if (cilen != CILEN_NETN || \
710             citype != opt) \
711             break; \
712         GETLONG(cilong, p); \
713         if (cilong != val) \
714             break; \
715         IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected long opt %d", opt)); \
716     }
717
718 #define REJCICHARS(opt, neg, val, cnt) \
719     if (neg) { \
720         int indx, count = cnt; \
721         neg = 0; \
722         len -= (count + 2); \
723         if (len < 0) \
724             break; \
725         GETCHAR(citype, p); \
726         GETCHAR(cilen, p); \
727         if (cilen != (count + 2) || \
728             citype != opt) \
729             break; \
730         for (indx = 0; indx < count; ++indx) {\
731             GETCHAR(cichar, p); \
732             if (cichar != ((u_char *) &val)[indx]) \
733                break; \
734         }\
735         if (indx != count) \
736             break; \
737         IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected opt %d", opt)); \
738     }
739
740 #define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val))
741 #define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val))
742
743 #define REJCIVOID(opt, neg) \
744     if (neg) { \
745         neg = 0; \
746         if ((len -= CILEN_VOID) < 0) \
747             break; \
748         GETCHAR(citype, p); \
749         GETCHAR(cilen, p); \
750         if (cilen != CILEN_VOID || citype != opt) \
751             break; \
752         IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected void opt %d", opt)); \
753     }
754
755 #define REJCIPROTO(opt, neg, val, bit) \
756     if (neg && (val & BIT(bit))) \
757       { \
758         if (len < 2) \
759             break; \
760         GETCHAR(citype, p); \
761         GETCHAR(cilen, p); \
762         if (cilen != CILEN_PROTOCOL || citype != opt) \
763             break; \
764         len -= cilen; \
765         if (len < 0) \
766             break; \
767         GETSHORT(cishort, p); \
768         if (cishort != (bit)) \
769             break; \
770         IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected router proto %d", bit)); \
771         val &= ~BIT(bit); \
772         if (val == 0) \
773             neg = 0; \
774       }
775
776 /*
777  * Any Rejected CIs must be in exactly the same order that we sent.
778  * Check packet length and CI length at each step.
779  * If we find any deviations, then this packet is bad.
780  */
781     try = *go;
782
783     do {
784         REJCINETWORK (IPX_NETWORK_NUMBER,  try.neg_nn,     try.our_network);
785         REJCINODE    (IPX_NODE_NUMBER,     try.neg_node,   try.our_node);
786         REJCIPROTO   (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 0);
787         REJCIPROTO   (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 2);
788         REJCIPROTO   (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 4);
789         REJCINAME    (IPX_ROUTER_NAME,     try.neg_name,   try.name);
790         REJCIVOID    (IPX_COMPLETE,        try.neg_complete);
791 /*
792  * This is the end of the record.
793  */
794         if (len == 0) {
795             if (f->state != OPENED)
796                 *go = try;
797             return (1);
798         }
799     } while (0);
800 /*
801  * The frame is invalid at this point.
802  */
803     IPXCPDEBUG((LOG_INFO, "ipxcp_rejci: received bad Reject!"));
804     return 0;
805 }
806
807 /*
808  * ipxcp_reqci - Check the peer's requested CIs and send appropriate response.
809  *
810  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
811  * appropriately.  If reject_if_disagree is non-zero, doesn't return
812  * CONFNAK; returns CONFREJ if it can't return CONFACK.
813  */
814 static int
815 ipxcp_reqci(f, inp, len, reject_if_disagree)
816     fsm *f;
817     u_char *inp;                /* Requested CIs */
818     int *len;                   /* Length of requested CIs */
819     int reject_if_disagree;
820 {
821     int unit = f->unit;
822     u_char *cip, *next;         /* Pointer to current and next CIs */
823     u_short cilen, citype;      /* Parsed len, type */
824     u_short cishort, ts;        /* Parsed short value */
825     u_int32_t tl, cinetwork, outnet;/* Parsed address values */
826     int rc = CONFACK;           /* Final packet return code */
827     int orc;                    /* Individual option return code */
828     u_char *p;                  /* Pointer to next char to parse */
829     u_char *ucp = inp;          /* Pointer to current output char */
830     int l = *len;               /* Length left */
831     u_char maxslotindex, cflag;
832
833     /*
834      * Reset all his options.
835      */
836     BZERO(ho, sizeof(*ho));
837     
838     /*
839      * Process all his options.
840      */
841     next = inp;
842     while (l) {
843         orc = CONFACK;                  /* Assume success */
844         cip = p = next;                 /* Remember begining of CI */
845         if (l < 2 ||                    /* Not enough data for CI header or */
846             p[1] < 2 ||                 /*  CI length too small or */
847             p[1] > l) {                 /*  CI length too big? */
848             IPXCPDEBUG((LOG_INFO, "ipxcp_reqci: bad CI length!"));
849             orc = CONFREJ;              /* Reject bad CI */
850             cilen = l;                  /* Reject till end of packet */
851             l = 0;                      /* Don't loop again */
852             goto endswitch;
853         }
854         GETCHAR(citype, p);             /* Parse CI type */
855         GETCHAR(cilen, p);              /* Parse CI length */
856         l -= cilen;                     /* Adjust remaining length */
857         next += cilen;                  /* Step to next CI */
858
859         switch (citype) {               /* Check CI type */
860 /*
861  * The network number must match. Choose the larger of the two.
862  */
863         case IPX_NETWORK_NUMBER:
864             IPXCPDEBUG((LOG_INFO, "ipxcp: received Network Number request"));
865             
866             /* if we wont negotiate the network number or the length is wrong
867                then reject the option */
868             if ( !ao->neg_nn || cilen != CILEN_NETN ) {
869                 orc = CONFREJ;
870                 break;          
871             }
872             GETLONG(cinetwork, p);
873             IPXCPDEBUG((LOG_INFO,"Remote proposed IPX network number is %8Lx",tl));
874
875             /* If the network numbers match then acknowledge them. */
876             if (cinetwork != 0) {
877                 ho->his_network = cinetwork;
878                 ho->neg_nn      = 1;
879                 if (wo->our_network == cinetwork)
880                     break;
881 /*
882  * If the network number is not given or we don't accept their change or
883  * the network number is too small then NAK it.
884  */
885                 if (! ao->accept_network || cinetwork < wo->our_network) {
886                     DECPTR (sizeof (u_int32_t), p);
887                     PUTLONG (wo->our_network, p);
888                     orc = CONFNAK;
889                 }
890                 break;
891             }
892 /*
893  * The peer sent '0' for the network. Give it ours if we have one.
894  */
895             if (go->our_network != 0) {
896                 DECPTR (sizeof (u_int32_t), p);
897                 PUTLONG (wo->our_network, p);
898                 orc = CONFNAK;
899 /*
900  * We don't have one. Reject the value.
901  */
902             } else
903                 orc = CONFREJ;
904
905             break;
906 /*
907  * The node number is required
908  */
909         case IPX_NODE_NUMBER:
910             IPXCPDEBUG((LOG_INFO, "ipxcp: received Node Number request"));
911
912             /* if we wont negotiate the node number or the length is wrong
913                then reject the option */
914             if ( cilen != CILEN_NODEN ) {
915                 orc = CONFREJ;
916                 break;
917             }
918
919             copy_node (p, ho->his_node);
920             ho->neg_node = 1;
921 /*
922  * If the remote does not have a number and we do then NAK it with the value
923  * which we have for it. (We never have a default value of zero.)
924  */
925             if (zero_node (ho->his_node)) {
926                 orc = CONFNAK;
927                 copy_node (wo->his_node, p);
928                 INCPTR (sizeof (wo->his_node), p);
929                 break;
930             }
931 /*
932  * If you have given me the expected network node number then I'll accept
933  * it now.
934  */
935             if (compare_node (wo->his_node, ho->his_node)) {
936                 orc = CONFACK;
937                 ho->neg_node = 1;
938                 INCPTR (sizeof (wo->his_node), p);
939                 break;
940             }
941 /*
942  * If his node number is the same as ours then ask him to try the next
943  * value.
944  */
945             if (compare_node (ho->his_node, go->our_node)) {
946                 inc_node (ho->his_node);
947                 orc = CONFNAK;
948                 copy_node (ho->his_node, p);
949                 INCPTR (sizeof (wo->his_node), p);
950                 break;
951             }
952 /*
953  * If we don't accept a new value then NAK it.
954  */
955             if (! ao->accept_remote) {
956                 copy_node (wo->his_node, p);
957                 INCPTR (sizeof (wo->his_node), p);
958                 orc = CONFNAK;
959                 break;
960             }
961             orc = CONFACK;
962             ho->neg_node = 1;
963             INCPTR (sizeof (wo->his_node), p);
964             break;
965 /*
966  * Compression is not desired at this time. It is always rejected.
967  */
968         case IPX_COMPRESSION_PROTOCOL:
969             IPXCPDEBUG((LOG_INFO, "ipxcp: received Compression Protocol request "));
970             orc = CONFREJ;
971             break;
972 /*
973  * The routing protocol is a bitmask of various types. Any combination
974  * of the values 2 and 4 are permissible. '0' for no routing protocol must
975  * be specified only once.
976  */
977         case IPX_ROUTER_PROTOCOL:
978             if ( !ao->neg_router || cilen < CILEN_PROTOCOL ) {
979                 orc = CONFREJ;
980                 break;          
981             }
982
983             GETSHORT (cishort, p);
984             IPXCPDEBUG((LOG_INFO,
985                         "Remote router protocol number %d",
986                         cishort));
987
988             if ((cishort == 0 && ho->router != 0) || (ho->router & BIT(0))) {
989                 orc = CONFREJ;
990                 break;          
991             }
992
993             if (cishort != 0 && cishort != 2 && cishort != 4) {
994                 orc = CONFREJ;
995                 break;
996             }
997
998             if (ho->router & BIT (cishort)) {
999                 orc = CONFREJ;
1000                 break;
1001             }
1002
1003             ho->router    |= BIT (cishort);
1004             ho->neg_router = 1;
1005             break;
1006 /*
1007  * The router name is advisorary. Just accept it if it is not too large.
1008  */
1009         case IPX_ROUTER_NAME:
1010             IPXCPDEBUG((LOG_INFO, "ipxcp: received Router Name request"));
1011             if (cilen >= CILEN_NAME) {
1012                 int name_size = cilen - CILEN_NAME;
1013                 if (name_size > sizeof (ho->name))
1014                     name_size = sizeof (ho->name) - 1;
1015                 memset (ho->name, 0, sizeof (ho->name));
1016                 memcpy (ho->name, p, name_size);
1017                 ho->name [name_size] = '\0';
1018                 ho->neg_name = 1;
1019                 orc = CONFACK;
1020                 break;
1021             }
1022             orc = CONFREJ;
1023             break;
1024 /*
1025  * This is advisorary.
1026  */
1027         case IPX_COMPLETE:
1028             IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request"));
1029             if (cilen != CILEN_COMPLETE)
1030                 orc = CONFREJ;
1031             else {
1032                 ho->neg_complete = 1;
1033                 orc = CONFACK;
1034             }
1035             break;
1036 /*
1037  * All other entries are not known at this time.
1038  */
1039         default:
1040             IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request"));
1041             orc = CONFREJ;
1042             break;
1043         }
1044
1045 endswitch:
1046         IPXCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
1047
1048         if (orc == CONFACK &&           /* Good CI */
1049             rc != CONFACK)              /*  but prior CI wasnt? */
1050             continue;                   /* Don't send this one */
1051
1052         if (orc == CONFNAK) {           /* Nak this CI? */
1053             if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
1054                 orc = CONFREJ;          /* Get tough if so */
1055             if (rc == CONFREJ)          /* Rejecting prior CI? */
1056                 continue;               /* Don't send this one */
1057             if (rc == CONFACK) {        /* Ack'd all prior CIs? */
1058                 rc  = CONFNAK;          /* Not anymore... */
1059                 ucp = inp;              /* Backup */
1060             }
1061         }
1062
1063         if (orc == CONFREJ &&           /* Reject this CI */
1064             rc != CONFREJ) {            /*  but no prior ones? */
1065             rc = CONFREJ;
1066             ucp = inp;                  /* Backup */
1067         }
1068
1069         /* Need to move CI? */
1070         if (ucp != cip)
1071             BCOPY(cip, ucp, cilen);     /* Move it */
1072
1073         /* Update output pointer */
1074         INCPTR(cilen, ucp);
1075     }
1076
1077     /*
1078      * If we aren't rejecting this packet, and we want to negotiate
1079      * their address, and they didn't send their address, then we
1080      * send a NAK with a IPX_NODE_NUMBER option appended. We assume the
1081      * input buffer is long enough that we can append the extra
1082      * option safely.
1083      */
1084
1085     if (rc != CONFREJ && !ho->neg_node &&
1086         wo->req_nn && !reject_if_disagree) {
1087         u_char *ps;
1088         if (rc == CONFACK) {
1089             rc = CONFNAK;
1090             wo->req_nn = 0;             /* don't ask again */
1091             ucp = inp;                  /* reset pointer */
1092         }
1093
1094         if (zero_node (wo->his_node))
1095             inc_node (wo->his_node);
1096
1097         PUTCHAR (IPX_NODE_NUMBER, ucp);
1098         PUTCHAR (CILEN_NODEN, ucp);
1099         copy_node (wo->his_node, ucp);
1100         INCPTR (sizeof (wo->his_node), ucp);
1101     }
1102
1103     *len = ucp - inp;                   /* Compute output length */
1104     IPXCPDEBUG((LOG_INFO, "ipxcp: returning Configure-%s", CODENAME(rc)));
1105     return (rc);                        /* Return final code */
1106 }
1107
1108 /*
1109  * ipxcp_up - IPXCP has come UP.
1110  *
1111  * Configure the IP network interface appropriately and bring it up.
1112  */
1113
1114 static void
1115 ipxcp_up(f)
1116     fsm *f;
1117 {
1118     int unit = f->unit;
1119
1120     IPXCPDEBUG((LOG_INFO, "ipxcp: up"));
1121
1122     if (!ho->neg_nn)
1123         ho->his_network = wo->his_network;
1124
1125     if (!ho->neg_node)
1126         copy_node (wo->his_node, ho->his_node);
1127
1128     if (!wo->neg_node && !go->neg_node)
1129         copy_node (wo->our_node, go->our_node);
1130
1131     if (zero_node (go->our_node)) {
1132         IPXCPDEBUG((LOG_ERR, "Could not determine local IPX node address"));
1133         ipxcp_close(f->unit, "Could not determine local IPX node address");
1134         return;
1135     }
1136
1137     go->network = go->our_network;
1138     if (ho->his_network != 0 && ho->his_network > go->network)
1139         go->network = ho->his_network;
1140
1141     if (go->network == 0) {
1142         IPXCPDEBUG((LOG_ERR, "Could not determine network number"));
1143         ipxcp_close (unit, "Could not determine network number");
1144         return;
1145     }
1146
1147     /* bring the interface up */
1148     if (!sifup(unit)) {
1149         IPXCPDEBUG((LOG_WARNING, "sifup failed"));
1150         ipxcp_close(unit, "Interface configuration failed");
1151         return;
1152     }
1153
1154     /* set the network number for IPX */
1155     if (!sipxfaddr(unit, go->network, go->our_node)) {
1156         IPXCPDEBUG((LOG_WARNING, "sipxfaddr failed"));
1157         ipxcp_close(unit, "Interface configuration failed");
1158         return;
1159     }
1160
1161     /*
1162      * Execute the ipx-up script, like this:
1163      *  /etc/ppp/ipx-up interface tty speed local-IPX remote-IPX
1164      */
1165
1166     ipxcp_script (f, "/etc/ppp/ipx-up");
1167 }
1168
1169 /*
1170  * ipxcp_down - IPXCP has gone DOWN.
1171  *
1172  * Take the IP network interface down, clear its addresses
1173  * and delete routes through it.
1174  */
1175
1176 static void
1177 ipxcp_down(f)
1178     fsm *f;
1179 {
1180     u_int32_t ournn, network;
1181
1182     IPXCPDEBUG((LOG_INFO, "ipxcp: down"));
1183
1184     cipxfaddr (f->unit);
1185     sifdown(f->unit);
1186     ipxcp_script (f, "/etc/ppp/ipx-down");
1187 }
1188
1189
1190 /*
1191  * ipxcp_script - Execute a script with arguments
1192  * interface-name tty-name speed local-IPX remote-IPX networks.
1193  */
1194 static void
1195 ipxcp_script(f, script)
1196     fsm *f;
1197     char *script;
1198 {
1199     int  unit = f->unit;
1200     char strspeed[32],   strlocal[32],     strremote[32];
1201     char strnetwork[32], strpid[32];
1202     char *argv[14],      strproto_lcl[32], strproto_rmt[32];
1203
1204     sprintf (strpid,   "%d", getpid());
1205     sprintf (strspeed, "%d", baud_rate);
1206
1207     strproto_lcl[0] = '\0';
1208     if (go->neg_router) {
1209         if (go->router & BIT(2))
1210             strcpy (strproto_lcl, "RIP ");
1211         if (go->router & BIT(4))
1212             strcpy (strproto_lcl, "NLSP ");
1213     }
1214
1215     if (strproto_lcl[0] == '\0')
1216         strcpy (strproto_lcl, "NONE ");
1217
1218     strproto_lcl[strlen (strproto_lcl)-1] = '\0';
1219
1220     strproto_rmt[0] = '\0';
1221     if (ho->neg_router) {
1222         if (ho->router & BIT(2))
1223             strcpy (strproto_rmt, "RIP ");
1224         if (ho->router & BIT(4))
1225             strcpy (strproto_rmt, "NLSP ");
1226     }
1227
1228     if (strproto_rmt[0] == '\0')
1229         strcpy (strproto_rmt, "NONE ");
1230
1231     strproto_rmt[strlen (strproto_rmt)-1] = '\0';
1232
1233     strcpy (strnetwork, ipx_ntoa (go->network));
1234
1235     sprintf (strlocal,
1236              "%02X%02X%02X%02X%02X%02X",
1237              NODE(go->our_node));
1238
1239     sprintf (strremote,
1240              "%02X%02X%02X%02X%02X%02X",
1241              NODE(ho->his_node));
1242
1243     argv[0]  = script;
1244     argv[1]  = ifname;
1245     argv[2]  = devnam;
1246     argv[3]  = strspeed;
1247     argv[4]  = strnetwork;
1248     argv[5]  = strlocal;
1249     argv[6]  = strremote;
1250     argv[7]  = strproto_lcl;
1251     argv[8]  = strproto_rmt;
1252     argv[9]  = go->name;
1253     argv[10] = ho->name;
1254     argv[11] = ipparam;
1255     argv[12] = strpid;
1256     argv[13] = NULL;
1257     run_program(script, argv, 0);
1258 }
1259
1260 /*
1261  * ipxcp_printpkt - print the contents of an IPXCP packet.
1262  */
1263 static char *ipxcp_codenames[] = {
1264     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1265     "TermReq", "TermAck", "CodeRej"
1266 };
1267
1268 static int
1269 ipxcp_printpkt(p, plen, printer, arg)
1270     u_char *p;
1271     int plen;
1272     void (*printer) __P((void *, char *, ...));
1273     void *arg;
1274 {
1275     int code, id, len, olen;
1276     u_char *pstart, *optend;
1277     u_short cishort;
1278     u_int32_t cilong;
1279
1280     if (plen < HEADERLEN)
1281         return 0;
1282     pstart = p;
1283     GETCHAR(code, p);
1284     GETCHAR(id, p);
1285     GETSHORT(len, p);
1286     if (len < HEADERLEN || len > plen)
1287         return 0;
1288
1289     if (code >= 1 && code <= sizeof(ipxcp_codenames) / sizeof(char *))
1290         printer(arg, " %s", ipxcp_codenames[code-1]);
1291     else
1292         printer(arg, " code=0x%x", code);
1293     printer(arg, " id=0x%x", id);
1294     len -= HEADERLEN;
1295     switch (code) {
1296     case CONFREQ:
1297     case CONFACK:
1298     case CONFNAK:
1299     case CONFREJ:
1300         /* print option list */
1301         while (len >= 2) {
1302             GETCHAR(code, p);
1303             GETCHAR(olen, p);
1304             p -= 2;
1305             if (olen < CILEN_VOID || olen > len) {
1306                 break;
1307             }
1308             printer(arg, " <");
1309             len -= olen;
1310             optend = p + olen;
1311             switch (code) {
1312             case IPX_NETWORK_NUMBER:
1313                 if (olen == CILEN_NETN) {
1314                     p += CILEN_VOID;
1315                     GETLONG(cilong, p);
1316                     printer (arg, "network %s", ipx_ntoa (cilong));
1317                 }
1318                 break;
1319             case IPX_NODE_NUMBER:
1320                 if (olen == CILEN_NODEN) {
1321                     p += CILEN_VOID;
1322                     printer (arg, "node ");
1323                     while (p < optend) {
1324                         GETCHAR(code, p);
1325                         printer(arg, "%.2x", code);
1326                     }
1327                 }
1328                 break;
1329             case IPX_COMPRESSION_PROTOCOL:
1330                 if (olen == CILEN_COMPRESS) {
1331                     p += CILEN_VOID;
1332                     GETSHORT (cishort, p);
1333                     printer (arg, "compression %d", cishort);
1334                 }
1335                 break;
1336             case IPX_ROUTER_PROTOCOL:
1337                 if (olen == CILEN_PROTOCOL) {
1338                     p += CILEN_VOID;
1339                     GETSHORT (cishort, p);
1340                     printer (arg, "router proto %d", cishort);
1341                 }
1342                 break;
1343             case IPX_ROUTER_NAME:
1344                 if (olen >= CILEN_NAME) {
1345                     p += CILEN_VOID;
1346                     printer (arg, "router name \"");
1347                     while (p < optend) {
1348                         GETCHAR(code, p);
1349                         if (code >= 0x20 && code < 0x7E)
1350                             printer (arg, "%c", code);
1351                         else
1352                             printer (arg, " \\%.2x", code);
1353                     }
1354                     printer (arg, "\"");
1355                 }
1356                 break;
1357             case IPX_COMPLETE:
1358                 if (olen == CILEN_COMPLETE) {
1359                     p += CILEN_VOID;
1360                     printer (arg, "complete");
1361                 }
1362                 break;
1363             default:
1364                 break;
1365             }
1366
1367             while (p < optend) {
1368                 GETCHAR(code, p);
1369                 printer(arg, " %.2x", code);
1370             }
1371             printer(arg, ">");
1372         }
1373         break;
1374
1375     case TERMACK:
1376     case TERMREQ:
1377         if (len > 0 && *p >= ' ' && *p < 0x7f) {
1378             printer(arg, " ");
1379             print_string(p, len, printer, arg);
1380             p += len;
1381             len = 0;
1382         }
1383         break;
1384     }
1385
1386     /* print the rest of the bytes in the packet */
1387     for (; len > 0; --len) {
1388         GETCHAR(code, p);
1389         printer(arg, " %.2x", code);
1390     }
1391
1392     return p - pstart;
1393 }
1394 #endif /* ifdef IPX_CHANGE */