2 * ipxcp.c - PPP IPX Control Protocol.
4 * Copyright (c) 1989 Carnegie Mellon University.
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by Carnegie Mellon University. The name of the
13 * University may not be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 static char rcsid[] = "$Id: ipxcp.c,v 1.4 1996/10/08 06:43:36 paulus Exp $";
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
39 #include "pathnames.h"
42 ipxcp_options ipxcp_wantoptions[NUM_PPP]; /* Options that we want to request */
43 ipxcp_options ipxcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
44 ipxcp_options ipxcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
45 ipxcp_options ipxcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
47 #define wo (&ipxcp_wantoptions[0])
48 #define ao (&ipxcp_allowoptions[0])
49 #define go (&ipxcp_gotoptions[0])
50 #define ho (&ipxcp_hisoptions[0])
53 * Callbacks for fsm code. (CI = Configuration Information)
55 static void ipxcp_resetci __P((fsm *)); /* Reset our CI */
56 static int ipxcp_cilen __P((fsm *)); /* Return length of our CI */
57 static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
58 static int ipxcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
59 static int ipxcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
60 static int ipxcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
61 static int ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
62 static void ipxcp_up __P((fsm *)); /* We're UP */
63 static void ipxcp_down __P((fsm *)); /* We're DOWN */
64 static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */
66 fsm ipxcp_fsm[NUM_PPP]; /* IPXCP fsm structure */
68 static fsm_callbacks ipxcp_callbacks = { /* IPXCP callback routines */
69 ipxcp_resetci, /* Reset our Configuration Information */
70 ipxcp_cilen, /* Length of our Configuration Information */
71 ipxcp_addci, /* Add our Configuration Information */
72 ipxcp_ackci, /* ACK our Configuration Information */
73 ipxcp_nakci, /* NAK our Configuration Information */
74 ipxcp_rejci, /* Reject our Configuration Information */
75 ipxcp_reqci, /* Request peer's Configuration Information */
76 ipxcp_up, /* Called when fsm reaches OPENED state */
77 ipxcp_down, /* Called when fsm leaves OPENED state */
78 NULL, /* Called when we want the lower layer up */
79 NULL, /* Called when we want the lower layer down */
80 NULL, /* Called when Protocol-Reject received */
81 NULL, /* Retransmission is necessary */
82 NULL, /* Called to handle protocol-specific codes */
83 "IPXCP" /* String name of protocol */
87 * Protocol entry points.
90 static void ipxcp_init __P((int));
91 static void ipxcp_open __P((int));
92 static void ipxcp_close __P((int, char *));
93 static void ipxcp_lowerup __P((int));
94 static void ipxcp_lowerdown __P((int));
95 static void ipxcp_input __P((int, u_char *, int));
96 static void ipxcp_protrej __P((int));
97 static int ipxcp_printpkt __P((u_char *, int,
98 void (*) __P((void *, char *, ...)), void *));
100 struct protent ipxcp_protent = {
120 * Lengths of configuration options.
124 #define CILEN_COMPLETE 2 /* length of complete option */
125 #define CILEN_NETN 6 /* network number length option */
126 #define CILEN_NODEN 8 /* node number length option */
127 #define CILEN_PROTOCOL 4 /* Minimum length of routing protocol */
128 #define CILEN_NAME 3 /* Minimum length of router name */
129 #define CILEN_COMPRESS 4 /* Minimum length of compression protocol */
131 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \
132 (x) == CONFNAK ? "NAK" : "REJ")
134 /* Used in printing the node number */
135 #define NODE(base) base[0], base[1], base[2], base[3], base[4], base[5]
137 /* Used to generate the proper bit mask */
138 #define BIT(num) (1 << (num))
141 * Make a string representation of a network IP address.
149 sprintf(b, "%lx", ipxaddr);
155 * ipxcp_init - Initialize IPXCP.
161 fsm *f = &ipxcp_fsm[unit];
164 f->protocol = PPP_IPXCP;
165 f->callbacks = &ipxcp_callbacks;
166 fsm_init(&ipxcp_fsm[unit]);
168 memset (wo->name, 0, sizeof (wo->name));
169 memset (wo->our_node, 0, sizeof (wo->our_node));
170 memset (wo->his_node, 0, sizeof (wo->his_node));
173 wo->neg_complete = 1;
179 ao->neg_complete = 1;
182 ao->accept_local = 0;
183 ao->accept_remote = 0;
184 ao->accept_network = 0;
188 * Copy the node number
195 memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node));
199 * Compare node numbers
203 compare_node (src, dst)
206 return memcmp (dst, src, sizeof (ipxcp_wantoptions[0].our_node)) == 0;
210 * Is the node number zero?
218 for (indx = 0; indx < sizeof (ipxcp_wantoptions[0].our_node); ++indx)
219 if (node [indx] != 0)
225 * Increment the node number
239 PUTLONG (magic_num, outp);
243 * ipxcp_open - IPXCP is allowed to come up.
249 fsm_open(&ipxcp_fsm[unit]);
253 * ipxcp_close - Take IPXCP down.
256 ipxcp_close(unit, reason)
260 fsm_close(&ipxcp_fsm[unit], reason);
265 * ipxcp_lowerup - The lower layer is up.
271 fsm_lowerup(&ipxcp_fsm[unit]);
276 * ipxcp_lowerdown - The lower layer is down.
279 ipxcp_lowerdown(unit)
282 fsm_lowerdown(&ipxcp_fsm[unit]);
287 * ipxcp_input - Input IPXCP packet.
290 ipxcp_input(unit, p, len)
295 fsm_input(&ipxcp_fsm[unit], p, len);
300 * ipxcp_protrej - A Protocol-Reject was received for IPXCP.
302 * Pretend the lower layer went down, so we shut up.
308 fsm_lowerdown(&ipxcp_fsm[unit]);
313 * ipxcp_resetci - Reset our CI.
322 wo->req_node = wo->neg_node && ao->neg_node;
323 wo->req_nn = wo->neg_nn && ao->neg_nn;
325 if (wo->our_network == 0) {
327 ao->accept_network = 1;
330 * If our node number is zero then change it.
332 if (zero_node (wo->our_node)) {
333 inc_node (wo->our_node);
334 ao->accept_local = 1;
338 * If his node number is zero then change it.
340 if (zero_node (wo->his_node)) {
341 inc_node (wo->his_node);
342 ao->accept_remote = 1;
345 * Unless router protocol is suppressed then assume that we can do RIP.
347 if (! (wo->router & BIT(0)))
348 wo->router |= BIT(2);
350 * Router protocol is only negotiated if requested. Others force the
353 if (wo->router & (BIT(2) | BIT(4)))
356 * Start with these default values
362 * ipxcp_cilen - Return length of our CI.
371 len = go->neg_nn ? CILEN_NETN : 0;
372 len += go->neg_node ? CILEN_NODEN : 0;
373 len += go->neg_name ? CILEN_NAME + strlen (go->name) - 1 : 0;
374 len += go->neg_complete ? CILEN_COMPLETE : 0;
376 * Router protocol 0 is mutually exclusive with the others.
378 if (go->neg_router) {
379 if (go->router & BIT(0))
380 len += CILEN_PROTOCOL;
382 if (go->router & BIT(2))
383 len += CILEN_PROTOCOL;
384 if (go->router & BIT(4))
385 len += CILEN_PROTOCOL;
394 * ipxcp_addci - Add our desired CIs to a packet.
397 ipxcp_addci(f, ucp, lenp)
405 * Add the options to the record.
408 PUTCHAR (IPX_NETWORK_NUMBER, ucp);
409 PUTCHAR (CILEN_NETN, ucp);
410 PUTLONG (go->our_network, ucp);
415 PUTCHAR (IPX_NODE_NUMBER, ucp);
416 PUTCHAR (CILEN_NODEN, ucp);
417 for (indx = 0; indx < sizeof (go->our_node); ++indx)
418 PUTCHAR (go->our_node[indx], ucp);
422 int cilen = strlen (go->name);
424 PUTCHAR (IPX_ROUTER_NAME, ucp);
425 PUTCHAR (CILEN_NAME + cilen - 1, ucp);
426 for (indx = 0; indx < cilen; ++indx)
427 PUTCHAR (go->name [indx], ucp);
430 if (go->neg_router && (go->router & (BIT(0) | BIT(2) | BIT(4)))) {
431 PUTCHAR (IPX_ROUTER_PROTOCOL, ucp);
432 PUTCHAR (CILEN_PROTOCOL, ucp);
433 PUTSHORT (go->router, ucp);
436 if (go->neg_complete) {
437 PUTCHAR (IPX_COMPLETE, ucp);
438 PUTCHAR (CILEN_COMPLETE, ucp);
443 * ipxcp_ackci - Ack our CIs.
450 ipxcp_ackci(f, p, len)
456 u_short cilen, citype, cishort;
460 #define ACKCIVOID(opt, neg) \
462 if ((len -= CILEN_VOID) < 0) \
464 GETCHAR(citype, p); \
466 if (cilen != CILEN_VOID || \
471 #define ACKCICOMPLETE(opt,neg) ACKCIVOID(opt, neg)
473 #define ACKCICHARS(opt, neg, val, cnt) \
475 int indx, count = cnt; \
476 len -= (count + 2); \
479 GETCHAR(citype, p); \
481 if (cilen != (count + 2) || \
484 for (indx = 0; indx < count; ++indx) {\
485 GETCHAR(cichar, p); \
486 if (cichar != ((u_char *) &val)[indx]) \
493 #define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val))
494 #define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val))
496 #define ACKCINETWORK(opt, neg, val) \
498 if ((len -= CILEN_NETN) < 0) \
500 GETCHAR(citype, p); \
502 if (cilen != CILEN_NETN || \
505 GETLONG(cilong, p); \
510 #define ACKCIPROTO(opt, neg, val) \
511 if (neg && p[1] == CILEN_PROTOCOL && len >= p[1] && p[0] == opt) \
514 len -= CILEN_PROTOCOL; \
515 GETSHORT(cishort, p); \
516 if (cishort != (val)) \
520 * Process the ACK frame in the order in which the frame was assembled
523 ACKCINETWORK (IPX_NETWORK_NUMBER, go->neg_nn, go->our_network);
524 ACKCINODE (IPX_NODE_NUMBER, go->neg_node, go->our_node);
525 ACKCINAME (IPX_ROUTER_NAME, go->neg_name, go->name);
526 ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
527 ACKCICOMPLETE (IPX_COMPLETE, go->neg_complete);
529 * This is the end of the record.
535 * The frame is invalid
537 IPXCPDEBUG((LOG_INFO, "ipxcp_ackci: received bad Ack!"));
542 * ipxcp_nakci - Peer has sent a NAK for some of our CIs.
543 * This should not modify any state if the Nak is bad
544 * or if IPXCP is in the OPENED state.
552 ipxcp_nakci(f, p, len)
558 u_char citype, cilen, *next;
561 ipxcp_options no; /* options we've seen Naks for */
562 ipxcp_options try; /* options to request next time */
564 BZERO(&no, sizeof(no));
567 while (len > CILEN_VOID) {
573 next = &p [cilen - CILEN_VOID];
576 case IPX_NETWORK_NUMBER:
577 if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN))
582 IPXCPDEBUG((LOG_INFO, "local IP address %d", l));
583 if (l && ao->accept_network)
587 case IPX_NODE_NUMBER:
588 if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN))
592 IPXCPDEBUG((LOG_INFO,
593 "local node number %02X%02X%02X%02X%02X%02X",
596 if (!zero_node (p) && ao->accept_local &&
597 ! compare_node (p, ho->his_node))
598 copy_node (p, try.our_node);
601 /* These have never been sent. Ignore the NAK frame */
602 case IPX_COMPRESSION_PROTOCOL:
605 case IPX_ROUTER_PROTOCOL:
606 if (!go->neg_router || (cilen < CILEN_PROTOCOL))
610 if ((s != 0) && (s != 2) && (s != 4))
613 if (no.router & BIT(s))
616 if (no.router == 0) /* Reset on first NAK only */
619 try.router |= BIT(s);
622 IPXCPDEBUG((LOG_INFO, "Router protocol number %d", s));
625 /* These, according to the RFC, must never be NAKed. */
626 case IPX_ROUTER_NAME:
630 /* These are for options which we have not seen. */
637 /* If there is still anything left, this packet is bad. */
642 * Do not permit the peer to force a router protocol which we do not
645 try.router &= go->router;
646 if (try.router == 0 && go->router != 0) {
652 * OK, the Nak is good. Now we can update state.
654 if (f->state != OPENED)
660 IPXCPDEBUG((LOG_INFO, "ipxcp_nakci: received bad Nak!"));
665 * ipxcp_rejci - Reject some of our CIs.
668 ipxcp_rejci(f, p, len)
674 u_short cilen, citype, cishort;
677 ipxcp_options try; /* options to request next time */
679 #define REJCINETWORK(opt, neg, val) \
680 if (neg && p[1] == CILEN_NETN && len >= p[1] && p[0] == opt) { \
684 GETLONG(cilong, p); \
687 IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected network 0x%08x", val)); \
690 #define REJCICHARS(opt, neg, val, cnt) \
691 if (neg && p[1] == cnt + 2 && p[1] >= len && p[0] == opt) { \
692 int indx, count = cnt; \
696 for (indx = 0; indx < count; ++indx) {\
697 GETCHAR(cichar, p); \
698 if (cichar != ((u_char *) &val)[indx]) \
703 IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected opt %d", opt)); \
706 #define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val))
707 #define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val))
709 #define REJCIVOID(opt, neg) \
710 if (neg && p[1] == CILEN_VOID && len >= p[1] && p[0] == opt) { \
714 IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected void opt %d", opt)); \
717 #define REJCIPROTO(opt, neg, val) \
718 if (neg && p[1] == CILEN_PROTOCOL && len >= p[1] && p[0] == opt) \
721 len -= CILEN_PROTOCOL; \
722 GETSHORT(cishort, p); \
723 IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected router proto 0x%04x", cishort)); \
724 if ((cishort & val) == 0) \
732 * Any Rejected CIs must be in exactly the same order that we sent.
733 * Check packet length and CI length at each step.
734 * If we find any deviations, then this packet is bad.
739 REJCINETWORK (IPX_NETWORK_NUMBER, try.neg_nn, try.our_network);
740 REJCINODE (IPX_NODE_NUMBER, try.neg_node, try.our_node);
741 REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router);
742 REJCINAME (IPX_ROUTER_NAME, try.neg_name, try.name);
743 REJCIVOID (IPX_COMPLETE, try.neg_complete);
745 * This is the end of the record.
748 if (f->state != OPENED)
754 * The frame is invalid at this point.
756 IPXCPDEBUG((LOG_INFO, "ipxcp_rejci: received bad Reject!"));
761 * ipxcp_reqci - Check the peer's requested CIs and send appropriate response.
763 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
764 * appropriately. If reject_if_disagree is non-zero, doesn't return
765 * CONFNAK; returns CONFREJ if it can't return CONFACK.
768 ipxcp_reqci(f, inp, len, reject_if_disagree)
770 u_char *inp; /* Requested CIs */
771 int *len; /* Length of requested CIs */
772 int reject_if_disagree;
775 u_char *cip, *next; /* Pointer to current and next CIs */
776 u_short cilen, citype; /* Parsed len, type */
777 u_short cishort, ts; /* Parsed short value */
778 u_int32_t tl, cinetwork, outnet;/* Parsed address values */
779 int rc = CONFACK; /* Final packet return code */
780 int orc; /* Individual option return code */
781 u_char *p; /* Pointer to next char to parse */
782 u_char *ucp = inp; /* Pointer to current output char */
783 int l = *len; /* Length left */
784 u_char maxslotindex, cflag;
787 * Reset all his options.
789 BZERO(ho, sizeof(*ho));
792 * Process all his options.
796 orc = CONFACK; /* Assume success */
797 cip = p = next; /* Remember begining of CI */
798 if (l < 2 || /* Not enough data for CI header or */
799 p[1] < 2 || /* CI length too small or */
800 p[1] > l) { /* CI length too big? */
801 IPXCPDEBUG((LOG_INFO, "ipxcp_reqci: bad CI length!"));
802 orc = CONFREJ; /* Reject bad CI */
803 cilen = l; /* Reject till end of packet */
804 l = 0; /* Don't loop again */
807 GETCHAR(citype, p); /* Parse CI type */
808 GETCHAR(cilen, p); /* Parse CI length */
809 l -= cilen; /* Adjust remaining length */
810 next += cilen; /* Step to next CI */
812 switch (citype) { /* Check CI type */
814 * The network number must match. Choose the larger of the two.
816 case IPX_NETWORK_NUMBER:
817 IPXCPDEBUG((LOG_INFO, "ipxcp: received Network Number request"));
819 /* if we wont negotiate the network number or the length is wrong
820 then reject the option */
821 if ( !ao->neg_nn || cilen != CILEN_NETN ) {
825 GETLONG(cinetwork, p);
826 IPXCPDEBUG((LOG_INFO,"Remote proposed IPX network number is %8Lx",tl));
828 /* If the network numbers match then acknowledge them. */
829 if (cinetwork != 0) {
830 ho->his_network = cinetwork;
832 if (wo->our_network == cinetwork)
835 * If the network number is not given or we don't accept their change or
836 * the network number is too small then NAK it.
838 if (! ao->accept_network || cinetwork < wo->our_network) {
839 DECPTR (sizeof (u_int32_t), p);
840 PUTLONG (wo->our_network, p);
846 * The peer sent '0' for the network. Give it ours if we have one.
848 if (go->our_network != 0) {
849 DECPTR (sizeof (u_int32_t), p);
850 PUTLONG (wo->our_network, p);
853 * We don't have one. Reject the value.
860 * The node number is required
862 case IPX_NODE_NUMBER:
863 IPXCPDEBUG((LOG_INFO, "ipxcp: received Node Number request"));
865 /* if we wont negotiate the node number or the length is wrong
866 then reject the option */
867 if ( cilen != CILEN_NODEN ) {
872 copy_node (p, ho->his_node);
875 * If the remote does not have a number and we do then NAK it with the value
876 * which we have for it. (We never have a default value of zero.)
878 if (zero_node (ho->his_node)) {
880 copy_node (wo->his_node, p);
881 INCPTR (sizeof (wo->his_node), p);
885 * If you have given me the expected network node number then I'll accept
888 if (compare_node (wo->his_node, ho->his_node)) {
891 INCPTR (sizeof (wo->his_node), p);
895 * If his node number is the same as ours then ask him to try the next
898 if (compare_node (ho->his_node, go->our_node)) {
899 inc_node (ho->his_node);
901 copy_node (ho->his_node, p);
902 INCPTR (sizeof (wo->his_node), p);
906 * If we don't accept a new value then NAK it.
908 if (! ao->accept_remote) {
909 copy_node (wo->his_node, p);
910 INCPTR (sizeof (wo->his_node), p);
916 INCPTR (sizeof (wo->his_node), p);
919 * Compression is not desired at this time. It is always rejected.
921 case IPX_COMPRESSION_PROTOCOL:
922 IPXCPDEBUG((LOG_INFO, "ipxcp: received Compression Protocol request "));
926 * The routing protocol is a bitmask of various types. Any combination
927 * of the values 2 and 4 are permissible. '0' for no routing protocol must
928 * be specified only once.
930 case IPX_ROUTER_PROTOCOL:
931 if ( !ao->neg_router || cilen < CILEN_PROTOCOL ) {
936 GETSHORT (cishort, p);
937 IPXCPDEBUG((LOG_INFO,
938 "Remote router protocol number %d",
941 if ((cishort == 0 && ho->router != 0) || (ho->router & BIT(0))) {
946 if (cishort != 0 && cishort != 2 && cishort != 4) {
951 if (ho->router & BIT (cishort)) {
956 ho->router |= BIT (cishort);
960 * The router name is advisorary. Just accept it if it is not too large.
962 case IPX_ROUTER_NAME:
963 IPXCPDEBUG((LOG_INFO, "ipxcp: received Router Name request"));
964 if (cilen >= CILEN_NAME) {
965 int name_size = cilen - CILEN_NAME;
966 if (name_size > sizeof (ho->name))
967 name_size = sizeof (ho->name) - 1;
968 memset (ho->name, 0, sizeof (ho->name));
969 memcpy (ho->name, p, name_size);
970 ho->name [name_size] = '\0';
978 * This is advisorary.
981 IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request"));
982 if (cilen != CILEN_COMPLETE)
985 ho->neg_complete = 1;
990 * All other entries are not known at this time.
993 IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request"));
999 IPXCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
1001 if (orc == CONFACK && /* Good CI */
1002 rc != CONFACK) /* but prior CI wasnt? */
1003 continue; /* Don't send this one */
1005 if (orc == CONFNAK) { /* Nak this CI? */
1006 if (reject_if_disagree) /* Getting fed up with sending NAKs? */
1007 orc = CONFREJ; /* Get tough if so */
1008 if (rc == CONFREJ) /* Rejecting prior CI? */
1009 continue; /* Don't send this one */
1010 if (rc == CONFACK) { /* Ack'd all prior CIs? */
1011 rc = CONFNAK; /* Not anymore... */
1012 ucp = inp; /* Backup */
1016 if (orc == CONFREJ && /* Reject this CI */
1017 rc != CONFREJ) { /* but no prior ones? */
1019 ucp = inp; /* Backup */
1022 /* Need to move CI? */
1024 BCOPY(cip, ucp, cilen); /* Move it */
1026 /* Update output pointer */
1031 * If we aren't rejecting this packet, and we want to negotiate
1032 * their address, and they didn't send their address, then we
1033 * send a NAK with a IPX_NODE_NUMBER option appended. We assume the
1034 * input buffer is long enough that we can append the extra
1038 if (rc != CONFREJ && !ho->neg_node &&
1039 wo->req_nn && !reject_if_disagree) {
1041 if (rc == CONFACK) {
1043 wo->req_nn = 0; /* don't ask again */
1044 ucp = inp; /* reset pointer */
1047 if (zero_node (wo->his_node))
1048 inc_node (wo->his_node);
1050 PUTCHAR (IPX_NODE_NUMBER, ucp);
1051 PUTCHAR (CILEN_NODEN, ucp);
1052 copy_node (wo->his_node, ucp);
1053 INCPTR (sizeof (wo->his_node), ucp);
1056 *len = ucp - inp; /* Compute output length */
1057 IPXCPDEBUG((LOG_INFO, "ipxcp: returning Configure-%s", CODENAME(rc)));
1058 return (rc); /* Return final code */
1062 * ipxcp_up - IPXCP has come UP.
1064 * Configure the IP network interface appropriately and bring it up.
1073 IPXCPDEBUG((LOG_INFO, "ipxcp: up"));
1076 ho->his_network = wo->his_network;
1079 copy_node (wo->his_node, ho->his_node);
1081 if (!wo->neg_node && !go->neg_node)
1082 copy_node (wo->our_node, go->our_node);
1084 if (zero_node (go->our_node)) {
1085 IPXCPDEBUG((LOG_ERR, "Could not determine local IPX node address"));
1086 ipxcp_close(f->unit, "Could not determine local IPX node address");
1090 go->network = go->our_network;
1091 if (ho->his_network != 0 && ho->his_network > go->network)
1092 go->network = ho->his_network;
1094 if (go->network == 0) {
1095 IPXCPDEBUG((LOG_ERR, "Could not determine network number"));
1096 ipxcp_close (unit, "Could not determine network number");
1100 /* bring the interface up */
1102 IPXCPDEBUG((LOG_WARNING, "sifup failed"));
1103 ipxcp_close(unit, "Interface configuration failed");
1107 /* set the network number for IPX */
1108 if (!sipxfaddr(unit, go->network, go->our_node)) {
1109 IPXCPDEBUG((LOG_WARNING, "sipxfaddr failed"));
1110 ipxcp_close(unit, "Interface configuration failed");
1115 * Execute the ipx-up script, like this:
1116 * /etc/ppp/ipx-up interface tty speed local-IPX remote-IPX
1119 ipxcp_script (f, _PATH_IPXUP);
1123 * ipxcp_down - IPXCP has gone DOWN.
1125 * Take the IP network interface down, clear its addresses
1126 * and delete routes through it.
1133 u_int32_t ournn, network;
1135 IPXCPDEBUG((LOG_INFO, "ipxcp: down"));
1137 cipxfaddr (f->unit);
1139 ipxcp_script (f, _PATH_IPXDOWN);
1144 * ipxcp_script - Execute a script with arguments
1145 * interface-name tty-name speed local-IPX remote-IPX networks.
1148 ipxcp_script(f, script)
1153 char strspeed[32], strlocal[32], strremote[32];
1154 char strnetwork[32], strpid[32];
1155 char *argv[14], strproto_lcl[32], strproto_rmt[32];
1157 sprintf (strpid, "%d", getpid());
1158 sprintf (strspeed, "%d", baud_rate);
1160 strproto_lcl[0] = '\0';
1161 if (go->neg_router) {
1162 if (go->router & BIT(2))
1163 strcpy (strproto_lcl, "RIP ");
1164 if (go->router & BIT(4))
1165 strcpy (strproto_lcl, "NLSP ");
1168 if (strproto_lcl[0] == '\0')
1169 strcpy (strproto_lcl, "NONE ");
1171 strproto_lcl[strlen (strproto_lcl)-1] = '\0';
1173 strproto_rmt[0] = '\0';
1174 if (ho->neg_router) {
1175 if (ho->router & BIT(2))
1176 strcpy (strproto_rmt, "RIP ");
1177 if (ho->router & BIT(4))
1178 strcpy (strproto_rmt, "NLSP ");
1181 if (strproto_rmt[0] == '\0')
1182 strcpy (strproto_rmt, "NONE ");
1184 strproto_rmt[strlen (strproto_rmt)-1] = '\0';
1186 strcpy (strnetwork, ipx_ntoa (go->network));
1189 "%02X%02X%02X%02X%02X%02X",
1190 NODE(go->our_node));
1193 "%02X%02X%02X%02X%02X%02X",
1194 NODE(ho->his_node));
1200 argv[4] = strnetwork;
1202 argv[6] = strremote;
1203 argv[7] = strproto_lcl;
1204 argv[8] = strproto_rmt;
1206 argv[10] = ho->name;
1210 run_program(script, argv, 0);
1214 * ipxcp_printpkt - print the contents of an IPXCP packet.
1216 static char *ipxcp_codenames[] = {
1217 "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1218 "TermReq", "TermAck", "CodeRej"
1222 ipxcp_printpkt(p, plen, printer, arg)
1225 void (*printer) __P((void *, char *, ...));
1228 int code, id, len, olen;
1229 u_char *pstart, *optend;
1233 if (plen < HEADERLEN)
1239 if (len < HEADERLEN || len > plen)
1242 if (code >= 1 && code <= sizeof(ipxcp_codenames) / sizeof(char *))
1243 printer(arg, " %s", ipxcp_codenames[code-1]);
1245 printer(arg, " code=0x%x", code);
1246 printer(arg, " id=0x%x", id);
1253 /* print option list */
1258 if (olen < CILEN_VOID || olen > len) {
1265 case IPX_NETWORK_NUMBER:
1266 if (olen == CILEN_NETN) {
1269 printer (arg, "network %s", ipx_ntoa (cilong));
1272 case IPX_NODE_NUMBER:
1273 if (olen == CILEN_NODEN) {
1275 printer (arg, "node ");
1276 while (p < optend) {
1278 printer(arg, "%.2x", code);
1282 case IPX_COMPRESSION_PROTOCOL:
1283 if (olen == CILEN_COMPRESS) {
1285 GETSHORT (cishort, p);
1286 printer (arg, "compression %d", cishort);
1289 case IPX_ROUTER_PROTOCOL:
1290 if (olen == CILEN_PROTOCOL) {
1292 GETSHORT (cishort, p);
1293 printer (arg, "router proto %d", cishort);
1296 case IPX_ROUTER_NAME:
1297 if (olen >= CILEN_NAME) {
1299 printer (arg, "router name \"");
1300 while (p < optend) {
1302 if (code >= 0x20 && code < 0x7E)
1303 printer (arg, "%c", code);
1305 printer (arg, " \\%.2x", code);
1307 printer (arg, "\"");
1311 if (olen == CILEN_COMPLETE) {
1313 printer (arg, "complete");
1320 while (p < optend) {
1322 printer(arg, " %.2x", code);
1330 if (len > 0 && *p >= ' ' && *p < 0x7f) {
1332 print_string(p, len, printer, arg);
1339 /* print the rest of the bytes in the packet */
1340 for (; len > 0; --len) {
1342 printer(arg, " %.2x", code);
1347 #endif /* ifdef IPX_CHANGE */