source: rtems/cpukit/pppd/ipxcp.c @ 0173ab8

4.104.114.84.9
Last change on this file since 0173ab8 was d0950ad, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 30, 1999 at 10:12:50 PM

Added port of ppp-2.3.5 from Tomasz Domin <dot@…> of ComArch? SA.
Tomasz only tested this on the mpc823.

The official site for the original source for this PPP implementation is:

ftp://cs.anu.edu.au/pub/software/ppp

NOTE: As of 11/30/1999, the current version of this source is 2.3.10.

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