📄 if_spppsubr.c
字号:
void sppp_attach (struct ifnet *ifp){ struct sppp *sp = (struct sppp*) ifp; /* Initialize keepalive handler. */ if (! spppq) timeout (sppp_keepalive, 0, hz * 10); /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; spppq = sp; sp->pp_if.if_type = IFT_PPP; sp->pp_if.if_output = sppp_output; sp->pp_fastq.ifq_maxlen = 32; sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; 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){ struct sppp **q, *p, *sp = (struct sppp*) ifp; /* Remove the entry from the keepalive list. */ for (q = &spppq; (p = *q); q = &p->pp_next) if (p == sp) { *q = p->pp_next; break; } /* Stop keepalive handler. */ if (! spppq) untimeout (sppp_keepalive, 0); UNTIMO (sp);}/* * Flush the interface output queue. */void sppp_flush (struct ifnet *ifp){ struct sppp *sp = (struct sppp*) ifp; qflush (&sp->pp_if.if_snd); qflush (&sp->pp_fastq);}/* * 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){ struct sppp *sp = (struct sppp*) ifp; struct mbuf *m; int s = splimp (); IF_DEQUEUE (&sp->pp_fastq, m); if (! m) IF_DEQUEUE (&sp->pp_if.if_snd, m); splx (s); return (m);}/* * Send keepalive packets, every 10 seconds. */void sppp_keepalive (void *dummy){ struct sppp *sp; int s = splimp (); 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)) continue; /* No keepalive in PPP mode if LCP not opened yet. */ if (! (sp->pp_flags & PP_CISCO) && sp->lcp.state != LCP_STATE_OPENED) continue; if (sp->pp_alivecnt == MAXALIVECNT) { /* No keepalive packets got. Stop the interface. */ 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_alivecnt <= MAXALIVECNT) ++sp->pp_alivecnt; if (sp->pp_flags & PP_CISCO) sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, sp->pp_rseq); else if (sp->lcp.state == LCP_STATE_OPENED) { long nmagic = htonl (sp->lcp.magic); sp->lcp.echoid = ++sp->pp_seq; sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, sp->lcp.echoid, 4, &nmagic); } } splx (s); timeout (sppp_keepalive, 0, hz * 10);}/* * Handle incoming PPP Link Control Protocol packets. */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; u_char *p, opt[6]; u_long rmagic; if (len < 4) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid lcp packet length: %d bytes\n", ifp->if_name, ifp->if_unit, len); return; } h = mtod (m, struct lcp_header*); if (ifp->if_flags & IFF_DEBUG) { 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 ((u_char*) (h+1), len-4); printf (">\n"); } if (len > ntohs (h->len)) len = ntohs (h->len); switch (h->type) { default: /* Unknown packet type -- send Code-Reject packet. */ 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); break; } 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); /* fall through... */ case LCP_STATE_ACK_SENT: /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; } break; } /* Send Configure-Ack packet. */ sp->pp_loopcnt = 0; sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, h->ident, len-4, h+1); /* Change the state. */ 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); 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); /* An ACK has already been sent. */ sp->lcp.state = LCP_STATE_ACK_SENT; break; } break; case LCP_CONF_ACK: 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; } break; case LCP_CONF_NAK: if (h->ident != sp->lcp.confid) break; p = (u_char*) (h+1); if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { 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->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; } /* 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->lcp.confid) break; UNTIMO (sp); /* 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_REQ: UNTIMO (sp); /* Send Terminate-Ack packet. */ sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; /* Initiate renegotiation. */ sppp_lcp_open (sp); break; case LCP_TERM_ACK: case LCP_CODE_REJ: case LCP_PROTO_REJ: /* Ignore for now. */ break; case LCP_DISC_REQ: /* Discard the packet. */ break; case LCP_ECHO_REQ: if (sp->lcp.state != LCP_STATE_OPENED) break; if (len < 8) { 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); break; } if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { /* 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.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); break; } if (ntohl (*(long*)(h+1)) != sp->lcp.magic) sp->pp_alivecnt = 0; break; }}/* * Handle incoming Cisco keepalive protocol packets. */void sppp_cisco_input (struct sppp *sp, struct mbuf *m){ struct cisco_packet *h; struct ifaddr *ifa; struct ifnet *ifp = &sp->pp_if; if (m->m_pkthdr.len != CISCO_PACKET_LEN) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid cisco packet length: %d bytes\n", ifp->if_name, ifp->if_unit, m->m_pkthdr.len); return; } 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", ifp->if_name, ifp->if_unit, m->m_pkthdr.len, ntohl (h->type), h->par1, h->par2, h->rel, h->time0, h->time1); switch (ntohl (h->type)) { default: if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: unknown cisco packet type: 0x%lx\n", ifp->if_name, ifp->if_unit, ntohl (h->type)); break; case CISCO_ADDR_REPLY: /* Reply on address request, ignore */ break; case CISCO_KEEPALIVE_REQ: 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; 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) if (ifa->ifa_addr->sa_family == AF_INET) break; if (! ifa) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: unknown address for cisco request\n", ifp->if_name, ifp->if_unit); return; } sppp_cisco_send (sp, CISCO_ADDR_REPLY, ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr), ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr)); break; }}/* * Send PPP LCP packet. */void sppp_cp_send (struct sppp *sp, u_short proto, u_char type, u_char ident, u_short len, void *data){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -