📄 syncppp.c
字号:
int sppp_do_ioctl(struct device *dev, struct ifreq *ifr, int cmd){ struct sppp *sp = &((struct ppp_device *)dev)->sppp; if(dev->flags&IFF_UP) return -EBUSY; if(!capable(CAP_NET_ADMIN)) return -EPERM; switch(cmd) { case SPPPIOCCISCO: sp->pp_flags|=PP_CISCO; dev->type = ARPHRD_HDLC; break; case SPPPIOCPPP: sp->pp_flags&=~PP_CISCO; dev->type = ARPHRD_PPP; break; case SPPPIOCDEBUG: sp->pp_flags&=~PP_DEBUG; if(ifr->ifr_flags) sp->pp_flags|=PP_DEBUG; break; default: return -EINVAL; } return 0;}EXPORT_SYMBOL(sppp_do_ioctl);void sppp_attach(struct ppp_device *pd){ struct device *dev=&pd->dev; struct sppp *sp = &pd->sppp; /* Initialize keepalive handler. */ if (! spppq) { init_timer(&sppp_keepalive_timer); sppp_keepalive_timer.expires=jiffies+10*HZ; sppp_keepalive_timer.function=sppp_keepalive; add_timer(&sppp_keepalive_timer); } /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; spppq = sp; sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; sp->pp_seq = 0; sp->pp_rseq = 0; sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/ sp->lcp.magic = 0; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sp->pp_if = dev; /* * Device specific setup. All but interrupt handler and * hard_start_xmit. */ dev->hard_header = sppp_hard_header; dev->rebuild_header = sppp_rebuild_header; dev->tx_queue_len = 10; dev->type = ARPHRD_HDLC; dev->addr_len = 0; dev->hard_header_len = sizeof(struct ppp_header); dev->mtu = PPP_MTU; /* * These 4 are callers but MUST also call sppp_ functions */ dev->do_ioctl = sppp_do_ioctl;#if 0 dev->get_stats = NULL; /* Let the driver override these */ dev->open = sppp_open; dev->stop = sppp_close;#endif dev->change_mtu = sppp_change_mtu; dev->hard_header_cache = NULL; dev->header_cache_update = NULL; dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; dev_init_buffers(dev);}EXPORT_SYMBOL(sppp_attach);void sppp_detach (struct device *dev){ struct sppp **q, *p, *sp = &((struct ppp_device *)dev)->sppp; /* 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) del_timer(&sppp_keepalive_timer); sppp_clear_timeout (sp);}EXPORT_SYMBOL(sppp_detach);/* * 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. */static intsppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, int len, u32 *magic){ u8 *buf, *r, *p; int rlen; len -= 4; buf = r = kmalloc (len, GFP_ATOMIC); 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 = (u32)p[2] << 24 | (u32)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. */ memcpy(r, p, p[1]); r += p[1]; rlen += p[1]; } if (rlen) sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); kfree(buf); return (rlen == 0);}static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb){ struct lcp_header *h; struct device *dev = sp->pp_if; int len = skb->len; if (len < 4) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n", dev->name, len); return; } h = (struct lcp_header *)skb->data; skb_pull(skb,sizeof(struct lcp_header)); if (sp->pp_flags & PP_DEBUG) { printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh", dev->name, len, sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); if (len > 4) sppp_print_bytes ((u8*) (h+1), len-4); printk (">\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_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h); break; case IPCP_CONF_REQ: if (len < 4) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n", dev->name, len); return; } if (len > 4) { sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, len-4, h+1); switch (sp->ipcp.state) { case IPCP_STATE_OPENED: /* Initiate renegotiation. */ sppp_ipcp_open (sp); /* 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); /* Change the state. */ 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: if (h->ident != sp->ipcp.confid) break; sppp_clear_timeout (sp); switch (sp->ipcp.state) { case IPCP_STATE_CLOSED: sp->ipcp.state = IPCP_STATE_ACK_RCVD; sppp_set_timeout (sp, 5); break; case IPCP_STATE_ACK_SENT: sp->ipcp.state = IPCP_STATE_OPENED; break; } break; case IPCP_CONF_NAK: case IPCP_CONF_REJ: if (h->ident != sp->ipcp.confid) break; sppp_clear_timeout (sp); /* 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_REQ: /* Send Terminate-Ack packet. */ sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); /* Go to closed state. */ sp->ipcp.state = IPCP_STATE_CLOSED; /* Initiate renegotiation. */ sppp_ipcp_open (sp); break; case IPCP_TERM_ACK: /* Ignore for now. */ case IPCP_CODE_REJ: /* Ignore for now. */ break; }}static void sppp_lcp_open (struct sppp *sp){ char opt[6]; if (! sp->lcp.magic) sp->lcp.magic = jiffies; opt[0] = LCP_OPT_MAGIC; opt[1] = sizeof (opt); opt[2] = sp->lcp.magic >> 24; opt[3] = sp->lcp.magic >> 16; opt[4] = sp->lcp.magic >> 8; opt[5] = sp->lcp.magic; sp->lcp.confid = ++sp->pp_seq; sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, sizeof (opt), &opt); sppp_set_timeout (sp, 2);}static void sppp_ipcp_open (struct sppp *sp){ sp->ipcp.confid = ++sp->pp_seq; sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0); sppp_set_timeout (sp, 2);}/* * Process PPP control protocol timeouts. */ static void sppp_cp_timeout (unsigned long arg){ struct sppp *sp = (struct sppp*) arg; unsigned long flags; save_flags(flags); cli(); sp->pp_flags &= ~PP_TIMO; if (! (sp->pp_if->flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) { restore_flags(flags); return; } switch (sp->lcp.state) { case LCP_STATE_CLOSED: /* No ACK for Configure-Request, retry. */ sppp_lcp_open (sp); break; case LCP_STATE_ACK_RCVD: /* ACK got, but no Configure-Request for peer, retry. */ sppp_lcp_open (sp); sp->lcp.state = LCP_STATE_CLOSED; break; case LCP_STATE_ACK_SENT: /* ACK sent but no ACK for Configure-Request, retry. */ sppp_lcp_open (sp); break; case LCP_STATE_OPENED: /* LCP is already OK, try IPCP. */ switch (sp->ipcp.state) { case IPCP_STATE_CLOSED: /* No ACK for Configure-Request, retry. */ sppp_ipcp_open (sp); break; case IPCP_STATE_ACK_RCVD: /* ACK got, but no Configure-Request for peer, retry. */ sppp_ipcp_open (sp); sp->ipcp.state = IPCP_STATE_CLOSED; break; case IPCP_STATE_ACK_SENT: /* ACK sent but no ACK for Configure-Request, retry. */ sppp_ipcp_open (sp); break; case IPCP_STATE_OPENED: /* IPCP is OK. */ break; } break; } restore_flags(flags);}static char *sppp_lcp_type_name (u8 type){ static char buf [8]; switch (type) { case LCP_CONF_REQ: return ("conf-req"); case LCP_CONF_ACK: return ("conf-ack"); case LCP_CONF_NAK: return ("conf-nack"); case LCP_CONF_REJ: return ("conf-rej"); case LCP_TERM_REQ: return ("term-req"); case LCP_TERM_ACK: return ("term-ack"); case LCP_CODE_REJ: return ("code-rej"); case LCP_PROTO_REJ: return ("proto-rej"); case LCP_ECHO_REQ: return ("echo-req"); case LCP_ECHO_REPLY: return ("echo-reply"); case LCP_DISC_REQ: return ("discard-req"); } sprintf (buf, "%xh", type); return (buf);}static char *sppp_ipcp_type_name (u8 type){ static char buf [8]; switch (type) { case IPCP_CONF_REQ: return ("conf-req"); case IPCP_CONF_ACK: return ("conf-ack"); case IPCP_CONF_NAK: return ("conf-nack"); case IPCP_CONF_REJ: return ("conf-rej"); case IPCP_TERM_REQ: return ("term-req"); case IPCP_TERM_ACK: return ("term-ack"); case IPCP_CODE_REJ: return ("code-rej"); } sprintf (buf, "%xh", type); return (buf);}static void sppp_print_bytes (u_char *p, u16 len){ printk (" %x", *p++); while (--len > 0) printk ("-%x", *p++);}/* * Protocol glue. This drives the deferred processing mode the poorer * cards use. */int sppp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *p){ sppp_input(dev,skb); return 0;}EXPORT_SYMBOL(sppp_rcv);struct packet_type sppp_packet_type={ 0, NULL, sppp_rcv, NULL, NULL};void sync_ppp_init(void){ printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"); printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n"); sppp_packet_type.type=htons(ETH_P_WAN_PPP); dev_add_pack(&sppp_packet_type);}#ifdef MODULEint init_module(void){ if(debug) debug=PP_DEBUG; sync_ppp_init(); return 0;}void cleanup_module(void){ dev_remove_pack(&sppp_packet_type);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -