OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [c/] [src/] [libnetworking/] [pppd/] [ipxcp.c] - Blame information for rev 1779

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1026 ivang
/*
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   "ipxcp.c,v 1.4 2002/01/31 21:40:47 joel Exp"
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
 
42
static const char rcsid[] = RCSID;
43
 
44
/* global vars */
45
ipxcp_options ipxcp_wantoptions[NUM_PPP];       /* Options that we want to request */
46
ipxcp_options ipxcp_gotoptions[NUM_PPP];        /* Options that peer ack'd */
47
ipxcp_options ipxcp_allowoptions[NUM_PPP];      /* Options we allow peer to request */
48
ipxcp_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
 */
58
static void ipxcp_resetci __P((fsm *)); /* Reset our CI */
59
static int  ipxcp_cilen __P((fsm *));           /* Return length of our CI */
60
static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
61
static int  ipxcp_ackci __P((fsm *, u_char *, int));    /* Peer ack'd our CI */
62
static int  ipxcp_nakci __P((fsm *, u_char *, int));    /* Peer nak'd our CI */
63
static int  ipxcp_rejci __P((fsm *, u_char *, int));    /* Peer rej'd our CI */
64
static int  ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
65
static void ipxcp_up __P((fsm *));              /* We're UP */
66
static void ipxcp_down __P((fsm *));            /* We're DOWN */
67
static void ipxcp_finished __P((fsm *));        /* Don't need lower layer */
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_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
 
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
static 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
 
196
static short int
197
to_external(internal)
198
short 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
 
214
static char *
215
ipx_ntoa(ipxaddr)
216
u_int32_t ipxaddr;
217
{
218
    static char b[64];
219
    slprintf(b, sizeof(b), "%x", ipxaddr);
220
    return b;
221
}
222
 
223
 
224
static u_char *
225
setipxnodevalue(src,dst)
226
u_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
 
250
static int
251
setipxnode(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
 
272
static int
273
setipxname (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
 */
308
static void
309
ipxcp_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
 
345
static void
346
copy_node (src, dst)
347
u_char *src, *dst;
348
{
349
    memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node));
350
}
351
 
352
/*
353
 * Compare node numbers
354
 */
355
 
356
static int
357
compare_node (src, dst)
358
u_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
 
367
static int
368
zero_node (node)
369
u_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
 
382
static void
383
inc_node (node)
384
u_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
 */
399
static void
400
ipxcp_open(unit)
401
    int unit;
402
{
403
    fsm_open(&ipxcp_fsm[unit]);
404
}
405
 
406
/*
407
 * ipxcp_close - Take IPXCP down.
408
 */
409
static void
410
ipxcp_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
 */
421
static void
422
ipxcp_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
 */
432
static void
433
ipxcp_lowerdown(unit)
434
    int unit;
435
{
436
    fsm_lowerdown(&ipxcp_fsm[unit]);
437
}
438
 
439
 
440
/*
441
 * ipxcp_input - Input IPXCP packet.
442
 */
443
static void
444
ipxcp_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
 */
458
static void
459
ipxcp_protrej(unit)
460
    int unit;
461
{
462
    fsm_lowerdown(&ipxcp_fsm[unit]);
463
}
464
 
465
 
466
/*
467
 * ipxcp_resetci - Reset our CI.
468
 */
469
static void
470
ipxcp_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
 
517
static int
518
ipxcp_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
 */
538
static void
539
ipxcp_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
 */
587
static int
588
ipxcp_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
 
694
static int
695
ipxcp_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
 
794
bad:
795
    IPXCPDEBUG(("ipxcp_nakci: received bad Nak!"));
796
    return 0;
797
}
798
 
799
/*
800
 * ipxcp_rejci - Reject some of our CIs.
801
 */
802
static int
803
ipxcp_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
 */
913
static int
914
ipxcp_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
        }
1150
endswitch:
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
 
1216
static void
1217
ipxcp_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
 
1288
static void
1289
ipxcp_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
 */
1307
static void
1308
ipxcp_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
 */
1318
static char *ipxcp_codenames[] = {
1319
    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1320
    "TermReq", "TermAck", "CodeRej"
1321
};
1322
 
1323
static int
1324
ipxcp_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 */

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.