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