source: rtems/cpukit/pppd/ipxcp.c @ 9c858e56

4.104.114.84.9
Last change on this file since 9c858e56 was 2f1b930, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 16, 2001 at 8:42:09 PM

2001-08-16 Mike Siers <mikes@…>

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