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