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