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