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