diff options
author | jkh <jkh@FreeBSD.org> | 1995-10-04 22:24:16 +0000 |
---|---|---|
committer | jkh <jkh@FreeBSD.org> | 1995-10-04 22:24:16 +0000 |
commit | 8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310 (patch) | |
tree | 2fe87f819c9da98ccb878d0641f4b626f15c348d /sys/net/if_spppsubr.c | |
parent | 1c1ef85e1307f05f0ae122e54088a9f8e7425ef7 (diff) | |
download | FreeBSD-src-8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310.zip FreeBSD-src-8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310.tar.gz |
This upgrades the driver for Cronyx-Sigma multiplexor boards
from version 1.2 to version 1.9.
Submitted by: Serge Vakulenko, <vak@cronyx.ru>
Diffstat (limited to 'sys/net/if_spppsubr.c')
-rw-r--r-- | sys/net/if_spppsubr.c | 569 |
1 files changed, 337 insertions, 232 deletions
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c index 38b60ca..e8a9576 100644 --- a/sys/net/if_spppsubr.c +++ b/sys/net/if_spppsubr.c @@ -12,7 +12,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.1, Thu Oct 27 21:13:59 MSK 1994 + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 */ #undef DEBUG @@ -53,7 +53,7 @@ #ifdef DEBUG #define print(s) printf s #else -#define print(s) /*void*/ +#define print(s) {/*void*/} #endif #define MAXALIVECNT 3 /* max. alive packets */ @@ -103,26 +103,26 @@ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ struct ppp_header { - unsigned char address; - unsigned char control; - unsigned short protocol; + u_char address; + u_char control; + u_short protocol; }; #define PPP_HEADER_LEN sizeof (struct ppp_header) struct lcp_header { - unsigned char type; - unsigned char ident; - unsigned short len; + u_char type; + u_char ident; + u_short len; }; #define LCP_HEADER_LEN sizeof (struct lcp_header) struct cisco_packet { - unsigned long type; - unsigned long par1; - unsigned long par2; - unsigned short rel; - unsigned short time0; - unsigned short time1; + u_long type; + u_long par1; + u_long par2; + u_short rel; + u_short time0; + u_short time1; }; #define CISCO_PACKET_LEN 18 @@ -134,27 +134,37 @@ struct sppp *spppq; * priority queue. To decide if traffic is interactive, we check that * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. */ -static unsigned short interactive_ports[8] = { +static u_short interactive_ports[8] = { 0, 513, 0, 0, 0, 21, 0, 23, }; #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) -void sppp_keepalive (void *dummy1); -void sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type, - unsigned char ident, unsigned short len, void *data); +/* + * Timeout routine activation macros. + */ +#define TIMO(p,s) if (! ((p)->pp_flags & PP_TIMO)) { \ + timeout (sppp_cp_timeout, (void*) (p), (s)*hz); \ + (p)->pp_flags |= PP_TIMO; } +#define UNTIMO(p) if ((p)->pp_flags & PP_TIMO) { \ + untimeout (sppp_cp_timeout, (void*) (p)); \ + (p)->pp_flags &= ~PP_TIMO; } + +void sppp_keepalive (void *dummy); +void sppp_cp_send (struct sppp *sp, u_short proto, u_char type, + u_char ident, u_short len, void *data); void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); void sppp_lcp_input (struct sppp *sp, struct mbuf *m); void sppp_cisco_input (struct sppp *sp, struct mbuf *m); -void sppp_lcp_conf_rej (struct sppp *sp, struct lcp_header *h); void sppp_ipcp_input (struct sppp *sp, struct mbuf *m); void sppp_lcp_open (struct sppp *sp); void sppp_ipcp_open (struct sppp *sp); -int sppp_lcp_conf_unknown_options (int len, unsigned char *p); +int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, + int len, u_long *magic); void sppp_cp_timeout (void *arg); -char *sppp_lcp_type_name (unsigned char type); -char *sppp_ipcp_type_name (unsigned char type); -void sppp_print_bytes (unsigned char *p, unsigned short len); +char *sppp_lcp_type_name (u_char type); +char *sppp_ipcp_type_name (u_char type); +void sppp_print_bytes (u_char *p, u_short len); /* * Flush interface queue. @@ -179,8 +189,9 @@ static void qflush (struct ifqueue *ifq) void sppp_input (struct ifnet *ifp, struct mbuf *m) { struct ppp_header *h; - struct sppp *sp; + struct sppp *sp = (struct sppp*) ifp; struct ifqueue *inq = 0; + int s; ifp->if_lastchange = time; if (ifp->if_flags & IFF_UP) @@ -211,12 +222,18 @@ invalid: if (ifp->if_flags & IFF_DEBUG) case PPP_ALLSTATIONS: if (h->control != PPP_UI) goto invalid; - sp = (struct sppp*) ifp; + if (sp->pp_flags & PP_CISCO) { + if (ifp->if_flags & IFF_DEBUG) + printf ("%s%d: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", + ifp->if_name, ifp->if_unit, + h->address, h->control, ntohs (h->protocol)); + goto drop; + } switch (ntohs (h->protocol)) { default: if (sp->lcp.state == LCP_STATE_OPENED) sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, - ++sp->pp_seq, m->m_pkthdr.len - 2, + ++sp->pp_seq, m->m_pkthdr.len + 2, &h->protocol); if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid input protocol <0x%x 0x%x 0x%x>\n", @@ -264,6 +281,13 @@ invalid: if (ifp->if_flags & IFF_DEBUG) case CISCO_MULTICAST: case CISCO_UNICAST: /* Don't check the control field here (RFC 1547). */ + if (! (sp->pp_flags & PP_CISCO)) { + if (ifp->if_flags & IFF_DEBUG) + printf ("%s%d: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", + ifp->if_name, ifp->if_unit, + h->address, h->control, ntohs (h->protocol)); + goto drop; + } switch (ntohs (h->protocol)) { default: ++ifp->if_noproto; @@ -292,15 +316,18 @@ invalid: if (ifp->if_flags & IFF_DEBUG) goto drop; /* Check queue. */ + s = splimp (); if (IF_QFULL (inq)) { /* Queue overflow. */ + IF_DROP (inq); + splx (s); if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: protocol queue overflow\n", ifp->if_name, ifp->if_unit); - IF_DROP (inq); goto drop; } IF_ENQUEUE (inq, m); + splx (s); } /* @@ -361,8 +388,15 @@ int sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct switch (dst->sa_family) { #ifdef INET case AF_INET: /* Internet Protocol */ - h->protocol = htons ((sp->pp_flags & PP_CISCO) ? - ETHERTYPE_IP : PPP_IP); + if (sp->pp_flags & PP_CISCO) + h->protocol = htons (ETHERTYPE_IP); + else if (sp->ipcp.state == IPCP_STATE_OPENED) + h->protocol = htons (PPP_IP); + else { + m_freem (m); + splx (s); + return (ENETDOWN); + } break; #endif #ifdef NS @@ -416,7 +450,7 @@ void sppp_attach (struct ifnet *ifp) /* Initialize keepalive handler. */ if (! spppq) - timeout (sppp_keepalive, (void *)0, hz * 10); + timeout (sppp_keepalive, 0, hz * 10); /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; @@ -427,10 +461,11 @@ void sppp_attach (struct ifnet *ifp) sp->pp_fastq.ifq_maxlen = 32; sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; - sp->lcp.magic = time.tv_sec + time.tv_usec; - sp->lcp.rmagic = 0; - sp->pp_seq = sp->lcp.magic; + sp->pp_seq = 0; sp->pp_rseq = 0; + sp->lcp.magic = 0; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; } void sppp_detach (struct ifnet *ifp) @@ -446,8 +481,8 @@ void sppp_detach (struct ifnet *ifp) /* Stop keepalive handler. */ if (! spppq) - untimeout (sppp_keepalive, (void *)0); - untimeout (sppp_cp_timeout, (void *)sp); + untimeout (sppp_keepalive, 0); + UNTIMO (sp); } /* @@ -462,6 +497,19 @@ void sppp_flush (struct ifnet *ifp) } /* + * Check if the output queue is empty. + */ +int sppp_isempty (struct ifnet *ifp) +{ + struct sppp *sp = (struct sppp*) ifp; + int empty, s = splimp (); + + empty = !sp->pp_fastq.ifq_head && !sp->pp_if.if_snd.ifq_head; + splx (s); + return (empty); +} + +/* * Get next packet to send. */ struct mbuf *sppp_dequeue (struct ifnet *ifp) @@ -480,8 +528,7 @@ struct mbuf *sppp_dequeue (struct ifnet *ifp) /* * Send keepalive packets, every 10 seconds. */ -void -sppp_keepalive (void *dummy1) +void sppp_keepalive (void *dummy) { struct sppp *sp; int s = splimp (); @@ -489,8 +536,13 @@ sppp_keepalive (void *dummy1) for (sp=spppq; sp; sp=sp->pp_next) { struct ifnet *ifp = &sp->pp_if; + /* Keepalive mode disabled or channel down? */ if (! (sp->pp_flags & PP_KEEPALIVE) || - ! (ifp->if_flags & IFF_RUNNING) || + ! (ifp->if_flags & IFF_RUNNING)) + continue; + + /* No keepalive in PPP mode if LCP not opened yet. */ + if (! (sp->pp_flags & PP_CISCO) && sp->lcp.state != LCP_STATE_OPENED) continue; @@ -499,10 +551,15 @@ sppp_keepalive (void *dummy1) printf ("%s%d: down\n", ifp->if_name, ifp->if_unit); if_down (ifp); qflush (&sp->pp_fastq); + if (! (sp->pp_flags & PP_CISCO)) { + /* Shut down the PPP link. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + UNTIMO (sp); + /* Initiate negotiation. */ + sppp_lcp_open (sp); + } } - if (sp->pp_loopcnt >= MAXALIVECNT) - printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit); - if (sp->pp_alivecnt <= MAXALIVECNT) ++sp->pp_alivecnt; if (sp->pp_flags & PP_CISCO) @@ -510,13 +567,13 @@ sppp_keepalive (void *dummy1) sp->pp_rseq); else if (sp->lcp.state == LCP_STATE_OPENED) { long nmagic = htonl (sp->lcp.magic); - sp->lcp.lastid = ++sp->pp_seq; + sp->lcp.echoid = ++sp->pp_seq; sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, - sp->lcp.lastid, 4, &nmagic); + sp->lcp.echoid, 4, &nmagic); } } splx (s); - timeout (sppp_keepalive, (void *)0, hz * 10); + timeout (sppp_keepalive, 0, hz * 10); } /* @@ -527,7 +584,8 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) struct lcp_header *h; struct ifnet *ifp = &sp->pp_if; int len = m->m_pkthdr.len; - unsigned char *p; + u_char *p, opt[6]; + u_long rmagic; if (len < 4) { if (ifp->if_flags & IFF_DEBUG) @@ -537,11 +595,18 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) } h = mtod (m, struct lcp_header*); if (ifp->if_flags & IFF_DEBUG) { - printf ("%s%d: lcp input: %d bytes <%s id=%xh len=%xh", - ifp->if_name, ifp->if_unit, len, + char state = '?'; + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: state = 'C'; break; + case LCP_STATE_ACK_RCVD: state = 'R'; break; + case LCP_STATE_ACK_SENT: state = 'S'; break; + case LCP_STATE_OPENED: state = 'O'; break; + } + printf ("%s%d: lcp input(%c): %d bytes <%s id=%xh len=%xh", + ifp->if_name, ifp->if_unit, state, len, sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); if (len > 4) - sppp_print_bytes ((unsigned char*) (h+1), len-4); + sppp_print_bytes ((u_char*) (h+1), len-4); printf (">\n"); } if (len > ntohs (h->len)) @@ -549,107 +614,128 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) switch (h->type) { default: /* Unknown packet type -- send Code-Reject packet. */ - sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, len, h); + sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, + m->m_pkthdr.len, h); break; case LCP_CONF_REQ: if (len < 4) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid lcp configure request packet length: %d bytes\n", ifp->if_name, ifp->if_unit, len); - return; + break; } - if (len>4 && sppp_lcp_conf_unknown_options (len-4, (unsigned char*) (h+1))) { - sppp_lcp_conf_rej (sp, h); - if (sp->lcp.state == LCP_STATE_OPENED) + if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) + goto badreq; + if (rmagic == sp->lcp.magic) { + /* Local and remote magics equal -- loopback? */ + if (sp->pp_loopcnt >= MAXALIVECNT*5) { + printf ("%s%d: loopback\n", + ifp->if_name, ifp->if_unit); + sp->pp_loopcnt = 0; + if (ifp->if_flags & IFF_UP) { + if_down (ifp); + qflush (&sp->pp_fastq); + } + } else if (ifp->if_flags & IFF_DEBUG) + printf ("%s%d: conf req: magic glitch\n", + ifp->if_name, ifp->if_unit); + ++sp->pp_loopcnt; + + /* MUST send Conf-Nack packet. */ + rmagic = ~sp->lcp.magic; + opt[0] = LCP_OPT_MAGIC; + opt[1] = sizeof (opt); + opt[2] = rmagic >> 24; + opt[3] = rmagic >> 16; + opt[4] = rmagic >> 8; + opt[5] = rmagic; + sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, + h->ident, sizeof (opt), &opt); +badreq: + switch (sp->lcp.state) { + case LCP_STATE_OPENED: /* Initiate renegotiation. */ sppp_lcp_open (sp); - if (sp->lcp.state != LCP_STATE_ACK_RCVD) { + /* fall through... */ + case LCP_STATE_ACK_SENT: /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; } - } else { - /* Extract remote magic number. */ - p = (unsigned char*) (h+1); - if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) - sp->lcp.rmagic = (unsigned long)p[2] << 24 | - (unsigned long)p[3] << 16 | - p[4] << 8 | p[5]; - if (sp->lcp.rmagic == sp->lcp.magic) { - /* Local and remote magics are equal -- loop? */ - sp->lcp.rmagic = ~sp->lcp.magic; - /* Send Configure-Nack packet. */ - p[2] = sp->lcp.rmagic >> 24; - p[3] = sp->lcp.rmagic >> 16; - p[4] = sp->lcp.rmagic >> 8; - p[5] = sp->lcp.rmagic; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, - h->ident, len-4, h+1); - if (sp->lcp.state != LCP_STATE_ACK_RCVD) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; + break; } - } else { /* Send Configure-Ack packet. */ sp->pp_loopcnt = 0; sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, h->ident, len-4, h+1); - if (sp->lcp.state == LCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_lcp_open (sp); /* Change the state. */ - if (sp->lcp.state == LCP_STATE_ACK_RCVD) { + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: + sp->lcp.state = LCP_STATE_ACK_SENT; + break; + case LCP_STATE_ACK_RCVD: sp->lcp.state = LCP_STATE_OPENED; sppp_ipcp_open (sp); - } else - sp->lcp.state = LCP_STATE_ACK_SENT; - } + break; + case LCP_STATE_OPENED: + /* Remote magic changed -- close session. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + break; } break; case LCP_CONF_ACK: - if (h->ident != sp->pp_seq) - return; - untimeout (sppp_cp_timeout, (void *)sp); + if (h->ident != sp->lcp.confid) + break; + UNTIMO (sp); + if (! (ifp->if_flags & IFF_UP) && + (ifp->if_flags & IFF_RUNNING)) { + /* Coming out of loopback mode. */ + ifp->if_flags |= IFF_UP; + printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); + } switch (sp->lcp.state) { case LCP_STATE_CLOSED: sp->lcp.state = LCP_STATE_ACK_RCVD; + TIMO (sp, 5); break; case LCP_STATE_ACK_SENT: sp->lcp.state = LCP_STATE_OPENED; sppp_ipcp_open (sp); break; - case LCP_STATE_ACK_RCVD: - case LCP_STATE_OPENED: - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - break; } break; case LCP_CONF_NAK: - if (h->ident != sp->pp_seq) - return; - p = (unsigned char*) (h+1); + if (h->ident != sp->lcp.confid) + break; + p = (u_char*) (h+1); if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { - sp->lcp.rmagic = (unsigned long)p[2] << 24 | - (unsigned long)p[3] << 16 | - p[4] << 8 | p[5]; - if (sp->lcp.rmagic == ~sp->lcp.magic) { + rmagic = (u_long)p[2] << 24 | + (u_long)p[3] << 16 | p[4] << 8 | p[5]; + if (rmagic == ~sp->lcp.magic) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: conf nak: magic glitch\n", ifp->if_name, ifp->if_unit); - ++sp->pp_loopcnt; - sp->lcp.magic = time.tv_sec + time.tv_usec; + sp->lcp.magic += time.tv_sec + time.tv_usec; + } else + sp->lcp.magic = rmagic; } + if (sp->lcp.state != LCP_STATE_ACK_SENT) { + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; } - /* Fall through. */ + /* The link will be renegotiated after timeout, + * to avoid endless req-nack loop. */ + UNTIMO (sp); + TIMO (sp, 2); + break; case LCP_CONF_REJ: - if (h->ident != sp->pp_seq) - return; - untimeout (sppp_cp_timeout, (void *)sp); + if (h->ident != sp->lcp.confid) + break; + UNTIMO (sp); /* Initiate renegotiation. */ sppp_lcp_open (sp); if (sp->lcp.state != LCP_STATE_ACK_SENT) { @@ -659,27 +745,16 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) } break; case LCP_TERM_REQ: + UNTIMO (sp); /* Send Terminate-Ack packet. */ sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); - if (sp->lcp.state == LCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_lcp_open (sp); /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case LCP_TERM_ACK: - if (h->ident != sp->pp_seq) - return; - if (sp->lcp.state == LCP_STATE_OPENED) /* Initiate renegotiation. */ sppp_lcp_open (sp); - if (sp->lcp.state != LCP_STATE_ACK_SENT) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } break; + case LCP_TERM_ACK: case LCP_CODE_REJ: case LCP_PROTO_REJ: /* Ignore for now. */ @@ -692,33 +767,35 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid lcp echo request packet length: %d bytes\n", ifp->if_name, ifp->if_unit, len); - return; + break; } if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { - if (ifp->if_flags & IFF_DEBUG) - printf ("%s%d: echo reply: magic glitch\n", - ifp->if_name, ifp->if_unit); - ++sp->pp_loopcnt; + /* Line loopback mode detected. */ + printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit); + if_down (ifp); + qflush (&sp->pp_fastq); + + /* Shut down the PPP link. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + UNTIMO (sp); + /* Initiate negotiation. */ + sppp_lcp_open (sp); + break; } *(long*)(h+1) = htonl (sp->lcp.magic); sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); break; case LCP_ECHO_REPLY: - if (h->ident != sp->lcp.lastid) - return; + if (h->ident != sp->lcp.echoid) + break; if (len < 8) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid lcp echo reply packet length: %d bytes\n", ifp->if_name, ifp->if_unit, len); - return; - } - if (ntohl (*(long*)(h+1)) == sp->lcp.magic) - return; - if (! (ifp->if_flags & IFF_UP) && - (ifp->if_flags & IFF_RUNNING)) { - ifp->if_flags |= IFF_UP; - printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); + break; } + if (ntohl (*(long*)(h+1)) != sp->lcp.magic) sp->pp_alivecnt = 0; break; } @@ -741,8 +818,7 @@ void sppp_cisco_input (struct sppp *sp, struct mbuf *m) } h = mtod (m, struct cisco_packet*); if (ifp->if_flags & IFF_DEBUG) - printf ("%s%d: cisco input: %d bytes " - "<%lxh %lxh %lxh %xh %xh-%xh>\n", + printf ("%s%d: cisco input: %d bytes <%lxh %lxh %lxh %xh %xh-%xh>\n", ifp->if_name, ifp->if_unit, m->m_pkthdr.len, ntohl (h->type), h->par1, h->par2, h->rel, h->time0, h->time1); @@ -756,22 +832,32 @@ void sppp_cisco_input (struct sppp *sp, struct mbuf *m) /* Reply on address request, ignore */ break; case CISCO_KEEPALIVE_REQ: - if (! (ifp->if_flags & IFF_UP) && - (ifp->if_flags & IFF_RUNNING)) { - ifp->if_flags |= IFF_UP; - printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); - } sp->pp_alivecnt = 0; sp->pp_rseq = ntohl (h->par1); if (sp->pp_seq == sp->pp_rseq) { /* Local and remote sequence numbers are equal. * Probably, the line is in loopback mode. */ + if (sp->pp_loopcnt >= MAXALIVECNT) { + printf ("%s%d: loopback\n", + ifp->if_name, ifp->if_unit); + sp->pp_loopcnt = 0; + if (ifp->if_flags & IFF_UP) { + if_down (ifp); + qflush (&sp->pp_fastq); + } + } ++sp->pp_loopcnt; /* Generate new local sequence number */ sp->pp_seq ^= time.tv_sec ^ time.tv_usec; - } else + break; + } sp->pp_loopcnt = 0; + if (! (ifp->if_flags & IFF_UP) && + (ifp->if_flags & IFF_RUNNING)) { + ifp->if_flags |= IFF_UP; + printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); + } break; case CISCO_ADDR_REQ: for (ifa=ifp->if_addrlist; ifa; ifa=ifa->ifa_next) @@ -793,8 +879,8 @@ void sppp_cisco_input (struct sppp *sp, struct mbuf *m) /* * Send PPP LCP packet. */ -void sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type, - unsigned char ident, unsigned short len, void *data) +void sppp_cp_send (struct sppp *sp, u_short proto, u_char type, + u_char ident, u_short len, void *data) { struct ppp_header *h; struct lcp_header *lh; @@ -829,7 +915,7 @@ void sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type, sppp_ipcp_type_name (lh->type), lh->ident, ntohs (lh->len)); if (len) - sppp_print_bytes ((unsigned char*) (lh+1), len); + sppp_print_bytes ((u_char*) (lh+1), len); printf (">\n"); } if (IF_QFULL (&sp->pp_fastq)) { @@ -851,7 +937,7 @@ void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) struct cisco_packet *ch; struct mbuf *m; struct ifnet *ifp = &sp->pp_if; - unsigned long t = (time.tv_sec - boottime.tv_sec) * 1000; + u_long t = (time.tv_sec - boottime.tv_sec) * 1000; MGETHDR (m, M_DONTWAIT, MT_DATA); if (! m) @@ -869,8 +955,8 @@ void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) ch->par1 = htonl (par1); ch->par2 = htonl (par2); ch->rel = -1; - ch->time0 = htons ((unsigned short) (t >> 16)); - ch->time1 = htons ((unsigned short) t); + ch->time0 = htons ((u_short) (t >> 16)); + ch->time1 = htons ((u_short) t); if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: cisco output: <%lxh %lxh %lxh %xh %xh-%xh>\n", @@ -890,35 +976,42 @@ void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) /* * Process an ioctl request. Called on low priority level. */ -int sppp_ioctl (struct ifnet *ifp, int cmd, caddr_t data) +int sppp_ioctl (struct ifnet *ifp, int cmd, void *data) { struct ifreq *ifr = (struct ifreq*) data; - struct sppp *sp; - int s; + struct sppp *sp = (struct sppp*) ifp; + int s, going_up, going_down; switch (cmd) { default: return (EINVAL); - case SIOCSIFADDR: case SIOCAIFADDR: case SIOCSIFDSTADDR: break; + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + /* fall through... */ + case SIOCSIFFLAGS: + if (sp->pp_flags & PP_CISCO) + break; s = splimp (); - if (! (ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING)) { - /* Interface is stopping. */ - sp = (struct sppp*) ifp; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_cp_send (sp, PPP_LCP, LCP_TERM_REQ, ++sp->pp_seq, - 0, 0); - } else if ((ifp->if_flags & IFF_UP) && ! (ifp->if_flags & IFF_RUNNING)) { - /* Interface is starting. */ - sp = (struct sppp*) ifp; + going_up = (ifp->if_flags & IFF_UP) && + ! (ifp->if_flags & IFF_RUNNING); + going_down = ! (ifp->if_flags & IFF_UP) && + (ifp->if_flags & IFF_RUNNING); + if (going_up || going_down) { + /* Shut down the PPP link. */ + ifp->if_flags &= ~IFF_RUNNING; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; + UNTIMO (sp); + } + if (going_up) { + /* Interface is starting -- initiate negotiation. */ + ifp->if_flags |= IFF_RUNNING; sppp_lcp_open (sp); } splx (s); @@ -960,35 +1053,56 @@ int sppp_ioctl (struct ifnet *ifp, int cmd, caddr_t data) return (0); } -int sppp_lcp_conf_unknown_options (int len, unsigned char *p) -{ - /* Analyze the LCP Configure-Request options list - * for the presence of unknown options. */ - while (len > 0) { - if (*p != LCP_OPT_MAGIC) - return (1); - len -= p[1]; - p += p[1]; - } - return (0); -} - -void sppp_lcp_conf_rej (struct sppp *sp, struct lcp_header *h) +/* + * Analyze the LCP Configure-Request options list + * for the presence of unknown options. + * If the request contains unknown options, build and + * send Configure-reject packet, containing only unknown options. + */ +int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, + int len, u_long *magic) { - /* The LCP Configure-Request contains unknown options. - * Send Configure-reject packet, containing only unknown options. */ - unsigned char buf [PP_MTU], *r = buf, *p = (void*) (h+1); - unsigned rlen = 0, len = h->len - 4; - - while (len > 0) { - if (*p != LCP_OPT_MAGIC) { + u_char *buf, *r, *p; + int rlen; + + len -= 4; + buf = r = malloc (len, M_TEMP, M_NOWAIT); + if (! buf) + return (0); + + p = (void*) (h+1); + for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { + switch (*p) { + case LCP_OPT_MAGIC: + /* Magic number -- extract. */ + if (len >= 6 && p[1] == 6) { + *magic = (u_long)p[2] << 24 | + (u_long)p[3] << 16 | p[4] << 8 | p[5]; + continue; + } + break; + case LCP_OPT_ASYNC_MAP: + /* Async control character map -- check to be zero. */ + if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && + ! p[4] && ! p[5]) + continue; + break; + case LCP_OPT_MRU: + /* Maximum receive unit -- always OK. */ + continue; + default: + /* Others not supported. */ + break; + } + /* Add the option to rejected list. */ bcopy (p, r, p[1]); r += p[1]; + rlen += p[1]; } - len -= p[1]; - p += p[1]; - } + if (rlen) sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); + free (buf, M_TEMP); + return (rlen == 0); } void sppp_ipcp_input (struct sppp *sp, struct mbuf *m) @@ -1009,7 +1123,7 @@ void sppp_ipcp_input (struct sppp *sp, struct mbuf *m) ifp->if_name, ifp->if_unit, len, sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); if (len > 4) - sppp_print_bytes ((unsigned char*) (h+1), len-4); + sppp_print_bytes ((u_char*) (h+1), len-4); printf (">\n"); } if (len > ntohs (h->len)) @@ -1029,51 +1143,46 @@ void sppp_ipcp_input (struct sppp *sp, struct mbuf *m) if (len > 4) { sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, len-4, h+1); - if (sp->lcp.state == LCP_STATE_OPENED && - sp->ipcp.state == IPCP_STATE_OPENED) + + switch (sp->ipcp.state) { + case IPCP_STATE_OPENED: /* Initiate renegotiation. */ sppp_ipcp_open (sp); - if (sp->ipcp.state != IPCP_STATE_ACK_RCVD) + /* fall through... */ + case IPCP_STATE_ACK_SENT: /* Go to closed state. */ sp->ipcp.state = IPCP_STATE_CLOSED; + } } else { /* Send Configure-Ack packet. */ sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, 0, 0); - if (sp->lcp.state == LCP_STATE_OPENED && - sp->ipcp.state == IPCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); /* Change the state. */ - sp->ipcp.state = (sp->ipcp.state == IPCP_STATE_ACK_RCVD) ? - IPCP_STATE_OPENED : IPCP_STATE_ACK_SENT; + if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) + sp->ipcp.state = IPCP_STATE_OPENED; + else + sp->ipcp.state = IPCP_STATE_ACK_SENT; } break; case IPCP_CONF_ACK: - untimeout (sppp_cp_timeout, (void *)sp); + if (h->ident != sp->ipcp.confid) + break; + UNTIMO (sp); switch (sp->ipcp.state) { case IPCP_STATE_CLOSED: sp->ipcp.state = IPCP_STATE_ACK_RCVD; + TIMO (sp, 5); break; case IPCP_STATE_ACK_SENT: sp->ipcp.state = IPCP_STATE_OPENED; break; - case IPCP_STATE_ACK_RCVD: - case IPCP_STATE_OPENED: - if (sp->lcp.state == LCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - break; } break; case IPCP_CONF_NAK: case IPCP_CONF_REJ: - untimeout (sppp_cp_timeout, (void *)sp); - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - if (sp->lcp.state == LCP_STATE_OPENED) + if (h->ident != sp->ipcp.confid) + break; + UNTIMO (sp); /* Initiate renegotiation. */ sppp_ipcp_open (sp); if (sp->ipcp.state != IPCP_STATE_ACK_SENT) @@ -1083,22 +1192,13 @@ void sppp_ipcp_input (struct sppp *sp, struct mbuf *m) case IPCP_TERM_REQ: /* Send Terminate-Ack packet. */ sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); - if (sp->lcp.state == LCP_STATE_OPENED && - sp->ipcp.state == IPCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); /* Go to closed state. */ sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case IPCP_TERM_ACK: - if (sp->lcp.state == LCP_STATE_OPENED && - sp->ipcp.state == IPCP_STATE_OPENED) /* Initiate renegotiation. */ sppp_ipcp_open (sp); - if (sp->ipcp.state != IPCP_STATE_ACK_SENT) - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; break; + case IPCP_TERM_ACK: + /* Ignore for now. */ case IPCP_CODE_REJ: /* Ignore for now. */ break; @@ -1109,7 +1209,7 @@ void sppp_lcp_open (struct sppp *sp) { char opt[6]; - /* Make new magic number. */ + if (! sp->lcp.magic) sp->lcp.magic = time.tv_sec + time.tv_usec; opt[0] = LCP_OPT_MAGIC; opt[1] = sizeof (opt); @@ -1117,27 +1217,32 @@ void sppp_lcp_open (struct sppp *sp) opt[3] = sp->lcp.magic >> 16; opt[4] = sp->lcp.magic >> 8; opt[5] = sp->lcp.magic; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, ++sp->pp_seq, + sp->lcp.confid = ++sp->pp_seq; + sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, sizeof (opt), &opt); - timeout (sppp_cp_timeout, (void *)sp, hz * 5); + TIMO (sp, 2); } void sppp_ipcp_open (struct sppp *sp) { - sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, ++sp->pp_seq, 0, 0); - timeout (sppp_cp_timeout, (void *)sp, hz * 5); + sp->ipcp.confid = ++sp->pp_seq; + sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0); + TIMO (sp, 2); } /* * Process PPP control protocol timeouts. */ -void -sppp_cp_timeout (void * arg) +void sppp_cp_timeout (void *arg) { struct sppp *sp = (struct sppp*) arg; - struct ifnet *ifp = &sp->pp_if; int s = splimp (); + sp->pp_flags &= ~PP_TIMO; + if (! (sp->pp_if.if_flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) { + splx (s); + return; + } switch (sp->lcp.state) { case LCP_STATE_CLOSED: /* No ACK for Configure-Request, retry. */ @@ -1177,7 +1282,7 @@ sppp_cp_timeout (void * arg) splx (s); } -char *sppp_lcp_type_name (unsigned char type) +char *sppp_lcp_type_name (u_char type) { static char buf [8]; switch (type) { @@ -1197,7 +1302,7 @@ char *sppp_lcp_type_name (unsigned char type) return (buf); } -char *sppp_ipcp_type_name (unsigned char type) +char *sppp_ipcp_type_name (u_char type) { static char buf [8]; switch (type) { @@ -1213,7 +1318,7 @@ char *sppp_ipcp_type_name (unsigned char type) return (buf); } -void sppp_print_bytes (unsigned char *p, unsigned short len) +void sppp_print_bytes (u_char *p, u_short len) { printf (" %x", *p++); while (--len > 0) |