?? ipxcp.c
字號:
}/* * ipxcp_resetci - Reset our CI. */static voidipxcp_resetci(f) fsm *f;{ wo->req_node = wo->neg_node && ao->neg_node; wo->req_nn = wo->neg_nn && ao->neg_nn; if (wo->our_network == 0) { wo->neg_node = 1; ao->accept_network = 1; }/* * If our node number is zero then change it. */ if (zero_node (wo->our_node)) { inc_node (wo->our_node); ao->accept_local = 1; wo->neg_node = 1; }/* * If his node number is zero then change it. */ if (zero_node (wo->his_node)) { inc_node (wo->his_node); ao->accept_remote = 1; }/* * If no routing agent was specified then we do RIP/SAP according to the * RFC documents. If you have specified something then OK. Otherwise, we * do RIP/SAP. */ if (ao->router == 0) { ao->router |= BIT(RIP_SAP); wo->router |= BIT(RIP_SAP); } /* Always specify a routing protocol unless it was REJected. */ wo->neg_router = 1;/* * Start with these default values */ *go = *wo;}/* * ipxcp_cilen - Return length of our CI. */static intipxcp_cilen(f) fsm *f;{ int len; len = go->neg_nn ? CILEN_NETN : 0; len += go->neg_node ? CILEN_NODEN : 0; len += go->neg_name ? CILEN_NAME + strlen (go->name) - 1 : 0; /* RFC says that defaults should not be included. */ if (go->neg_router && to_external(go->router) != RIP_SAP) len += CILEN_PROTOCOL; return (len);}/* * ipxcp_addci - Add our desired CIs to a packet. */static voidipxcp_addci(f, ucp, lenp) fsm *f; u_char *ucp; int *lenp;{/* * Add the options to the record. */ if (go->neg_nn) { PUTCHAR (IPX_NETWORK_NUMBER, ucp); PUTCHAR (CILEN_NETN, ucp); PUTLONG (go->our_network, ucp); } if (go->neg_node) { int indx; PUTCHAR (IPX_NODE_NUMBER, ucp); PUTCHAR (CILEN_NODEN, ucp); for (indx = 0; indx < sizeof (go->our_node); ++indx) PUTCHAR (go->our_node[indx], ucp); } if (go->neg_name) { int cilen = strlen (go->name); int indx; PUTCHAR (IPX_ROUTER_NAME, ucp); PUTCHAR (CILEN_NAME + cilen - 1, ucp); for (indx = 0; indx < cilen; ++indx) PUTCHAR (go->name [indx], ucp); } if (go->neg_router) { short external = to_external (go->router); if (external != RIP_SAP) { PUTCHAR (IPX_ROUTER_PROTOCOL, ucp); PUTCHAR (CILEN_PROTOCOL, ucp); PUTSHORT (external, ucp); } }}/* * ipxcp_ackci - Ack our CIs. * * Returns: * 0 - Ack was bad. * 1 - Ack was good. */static intipxcp_ackci(f, p, len) fsm *f; u_char *p; int len;{ u_short cilen, citype, cishort; u_char cichar; u_int32_t cilong;#define ACKCIVOID(opt, neg) \ if (neg) { \ if ((len -= CILEN_VOID) < 0) \ break; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_VOID || \ citype != opt) \ break; \ }#define ACKCICOMPLETE(opt,neg) ACKCIVOID(opt, neg)#define ACKCICHARS(opt, neg, val, cnt) \ if (neg) { \ int indx, count = cnt; \ len -= (count + 2); \ if (len < 0) \ break; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != (count + 2) || \ citype != opt) \ break; \ for (indx = 0; indx < count; ++indx) {\ GETCHAR(cichar, p); \ if (cichar != ((u_char *) &val)[indx]) \ break; \ }\ if (indx != count) \ break; \ }#define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val))#define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val))#define ACKCINETWORK(opt, neg, val) \ if (neg) { \ if ((len -= CILEN_NETN) < 0) \ break; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_NETN || \ citype != opt) \ break; \ GETLONG(cilong, p); \ if (cilong != val) \ break; \ }#define ACKCIPROTO(opt, neg, val) \ if (neg) { \ if (len < 2) \ break; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_PROTOCOL || citype != opt) \ break; \ len -= cilen; \ if (len < 0) \ break; \ GETSHORT(cishort, p); \ if (cishort != to_external (val) || cishort == RIP_SAP) \ break; \ }/* * Process the ACK frame in the order in which the frame was assembled */ do { ACKCINETWORK (IPX_NETWORK_NUMBER, go->neg_nn, go->our_network); ACKCINODE (IPX_NODE_NUMBER, go->neg_node, go->our_node); ACKCINAME (IPX_ROUTER_NAME, go->neg_name, go->name); if (len > 0) ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);/* * This is the end of the record. */ if (len == 0) return (1); } while (0);/* * The frame is invalid */ IPXCPDEBUG(("ipxcp_ackci: received bad Ack!")); return (0);}/* * ipxcp_nakci - Peer has sent a NAK for some of our CIs. * This should not modify any state if the Nak is bad * or if IPXCP is in the OPENED state. * * Returns: * 0 - Nak was bad. * 1 - Nak was good. */static intipxcp_nakci(f, p, len, treat_as_reject) fsm *f; u_char *p; int len; int treat_as_reject;{ u_char citype, cilen, *next; u_short s; u_int32_t l; ipxcp_options no; /* options we've seen Naks for */ ipxcp_options try; /* options to request next time */ BZERO(&no, sizeof(no)); try = *go; while (len >= CILEN_VOID) { GETCHAR (citype, p); GETCHAR (cilen, p); len -= cilen; if (cilen < CILEN_VOID || len < 0) goto bad; next = &p [cilen - CILEN_VOID]; switch (citype) { case IPX_NETWORK_NUMBER: if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN)) goto bad; no.neg_nn = 1; GETLONG(l, p); if (treat_as_reject) try.neg_nn = 0; else if (l && ao->accept_network) try.our_network = l; break; case IPX_NODE_NUMBER: if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN)) goto bad; no.neg_node = 1; if (treat_as_reject) try.neg_node = 0; else if (!zero_node (p) && ao->accept_local && ! compare_node (p, ho->his_node)) copy_node (p, try.our_node); break; /* This has never been sent. Ignore the NAK frame */ case IPX_COMPRESSION_PROTOCOL: goto bad; case IPX_ROUTER_PROTOCOL: if (!go->neg_router || (cilen < CILEN_PROTOCOL)) goto bad; GETSHORT (s, p); if (s > 15) /* This is just bad, but ignore for now. */ break; s = BIT(s); if (no.router & s) /* duplicate NAKs are always bad */ goto bad; if (no.router == 0) /* Reset on first NAK only */ try.router = 0; no.router |= s; try.router |= s; try.neg_router = 1; break; /* These, according to the RFC, must never be NAKed. */ case IPX_ROUTER_NAME: case IPX_COMPLETE: goto bad; /* These are for options which we have not seen. */ default: break; } p = next; } /* * Do not permit the peer to force a router protocol which we do not * support. However, default to the condition that will accept "NONE". */ try.router &= (ao->router | BIT(IPX_NONE)); if (try.router == 0 && ao->router != 0) try.router = BIT(IPX_NONE); if (try.router != 0) try.neg_router = 1; /* * OK, the Nak is good. Now we can update state. * If there are any options left, we ignore them. */ if (f->state != OPENED) *go = try; return 1;bad: IPXCPDEBUG(("ipxcp_nakci: received bad Nak!")); return 0;}/* * ipxcp_rejci - Reject some of our CIs. */static intipxcp_rejci(f, p, len) fsm *f; u_char *p; int len;{ u_short cilen, citype, cishort; u_char cichar; u_int32_t cilong; ipxcp_options try; /* options to request next time */#define REJCINETWORK(opt, neg, val) \ if (neg && p[0] == opt) { \ if ((len -= CILEN_NETN) < 0) \ break; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_NETN || \ citype != opt) \ break; \ GETLONG(cilong, p); \ if (cilong != val) \ break; \ neg = 0; \ }#define REJCICHARS(opt, neg, val, cnt) \ if (neg && p[0] == opt) { \ int indx, count = cnt; \ len -= (count + 2); \ if (len < 0) \ break; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != (count + 2) || \ citype != opt) \ break; \ for (indx = 0; indx < count; ++indx) {\ GETCHAR(cichar, p); \ if (cichar != ((u_char *) &val)[indx]) \ break; \ }\ if (indx != count) \ break; \ neg = 0; \ }#define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val))#define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val))#define REJCIVOID(opt, neg) \ if (neg && p[0] == opt) { \ if ((len -= CILEN_VOID) < 0) \ break; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_VOID || citype != opt) \ break; \ neg = 0; \ }/* a reject for RIP/SAP is invalid since we don't send it and you can't reject something which is not sent. (You can NAK, but you can't REJ.) */#define REJCIPROTO(opt, neg, val, bit) \ if (neg && p[0] == opt) { \ if ((len -= CILEN_PROTOCOL) < 0) \ break; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_PROTOCOL) \ break; \ GETSHORT(cishort, p); \ if (cishort != to_external (val) || cishort == RIP_SAP) \ break; \ neg = 0; \ }/* * Any Rejected CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ try = *go; do { REJCINETWORK (IPX_NETWORK_NUMBER, try.neg_nn, try.our_network); REJCINODE (IPX_NODE_NUMBER, try.neg_node, try.our_node); REJCINAME (IPX_ROUTER_NAME, try.neg_name, try.name); REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 0);/* * This is the end of the record. */ if (len == 0) { if (f->state != OPENED) *go = try; return (1); } } while (0);/* * The frame is invalid at this point. */ IPXCPDEBUG(("ipxcp_rejci: received bad Reject!")); return 0;}/* * ipxcp_reqci - Check the peer's requested CIs and send appropriate response. * * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified * appropriately. If reject_if_disagree is non-zero, doesn't return * CONFNAK; returns CONFREJ if it can't return CONFACK. */static intipxcp_reqci(f, inp, len, reject_if_disagree) fsm *f; u_char *inp; /* Requested CIs */ int *len; /* Length of requested CIs */ int reject_if_disagree;{ u_char *cip, *next; /* Pointer to current and next CIs */ u_short cilen, citype; /* Parsed len, type */ u_short cishort; /* Parsed short value */ u_int32_t cinetwork; /* Parsed address values */ int rc = CONFACK; /* Final packet return code */ int orc; /* Individual option return code */ u_char *p; /* Pointer to next char to parse */ u_char *ucp = inp; /* Pointer to current output char */ int l = *len; /* Length left */ /* * Reset all his options. */ BZERO(ho, sizeof(*ho)); /* * Process all his options. */ next = inp; while (l) { orc = CONFACK; /* Assume success */ cip = p = next; /* Remember begining of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ IPXCPDEBUG(("ipxcp_reqci: bad CI length!")); orc = CONFREJ; /* Reject bad CI */ cilen = l; /* Reject till end of packet */ l = 0; /* Don't loop again */ goto endswitch; } GETCHAR(citype, p); /* Parse CI type */ GETCHAR(cilen, p); /* Parse CI length */ l -= cilen; /* Adjust remaining length */ next += cilen; /* Step to next CI */ switch (citype) { /* Check CI type *//* * The network number must match. Choose the larger of the two. */ case IPX_NETWORK_NUMBER: /* if we wont negotiate the network number or the length is wrong then reject the option */ if ( !ao->neg_nn || cilen != CILEN_NETN ) { orc = CONFREJ; break; } GETLONG(cinetwork, p); /* If the network numbers match then acknowledge them. */ if (cinetwork != 0) { ho->his_network = cinetwork; ho->neg_nn = 1; if (wo->our_network == cinetwork) break;/* * If the network number is not given or we don't accept their change or * the network number is too small then NAK it. */ if (! ao->accept_network || cinetwork < wo->our_network) { DECPTR (sizeof (u_int32_t), p); PUTLONG (wo->our_network, p); orc = CONFNAK; } break; }/* * The peer sent '0' for the network. Give it ours if we have one. */ if (go->our_network != 0) { DECPTR (sizeof (u_int32_t), p);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -