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