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