📄 syncppp.c
字号:
if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) return -EINVAL; dev->mtu=new_mtu; return 0;}/** * sppp_do_ioctl - Ioctl handler for ppp/hdlc * @dev: Device subject to ioctl * @ifr: Interface request block from the user * @cmd: Command that is being issued * * This function handles the ioctls that may be issued by the user * to control the settings of a PPP/HDLC link. It does both busy * and security checks. This function is intended to be wrapped by * callers who wish to add additional ioctl calls of their own. */ int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ struct sppp *sp = (struct sppp *)sppp_of(dev); 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; case SPPPIOCGFLAGS: if(copy_to_user(ifr->ifr_data, &sp->pp_flags, sizeof(sp->pp_flags))) return -EFAULT; break; case SPPPIOCSFLAGS: if(copy_from_user(&sp->pp_flags, ifr->ifr_data, sizeof(sp->pp_flags))) return -EFAULT; break; default: return -EINVAL; } return 0;}EXPORT_SYMBOL(sppp_do_ioctl);/** * sppp_attach - attach synchronous PPP/HDLC to a device * @pd: PPP device to initialise * * This initialises the PPP/HDLC support on an interface. At the * time of calling the dev element must point to the network device * that this interface is attached to. The interface should not yet * be registered. */ void sppp_attach(struct ppp_device *pd){ struct net_device *dev = pd->dev; struct sppp *sp = &pd->sppp; unsigned long flags; /* Make sure embedding is safe for sppp_of */ BUG_ON(sppp_of(dev) != sp); spin_lock_irqsave(&spppq_lock, flags); /* 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; spin_unlock_irqrestore(&spppq_lock, flags); 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; spin_lock_init(&sp->lock); /* * 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;}EXPORT_SYMBOL(sppp_attach);/** * sppp_detach - release PPP resources from a device * @dev: Network device to release * * Stop and free up any PPP/HDLC resources used by this * interface. This must be called before the device is * freed. */ void sppp_detach (struct net_device *dev){ struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev); unsigned long flags; spin_lock_irqsave(&spppq_lock, flags); /* 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); spin_unlock_irqrestore(&spppq_lock, flags);}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 net_device *dev = sp->pp_if; int len = skb->len; if (!pskb_may_pull(skb, sizeof(struct lcp_header))) { 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, NULL); /* 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, NULL); /* 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, NULL); 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; spin_lock_irqsave(&sp->lock, flags); sp->pp_flags &= ~PP_TIMO; if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) { spin_unlock_irqrestore(&sp->lock, 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; } spin_unlock_irqrestore(&sp->lock, flags); sppp_flush_xmit();}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++);}/** * sppp_rcv - receive and process a WAN PPP frame * @skb: The buffer to process * @dev: The device it arrived on * @p: Unused * @orig_dev: Unused * * Protocol glue. This drives the deferred processing mode the poorer * cards use. This can be called directly by cards that do not have * timing constraints but is normally called from the network layer * after interrupt servicing to process frames queued via netif_rx. */static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev){ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; sppp_input(dev,skb); return 0;}static struct packet_type sppp_packet_type = { .type = __constant_htons(ETH_P_WAN_PPP), .func = sppp_rcv,};static char banner[] __initdata = KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n" KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & " "Jan \"Yenya\" Kasprzak.\n";static int __init sync_ppp_init(void){ if(debug) debug=PP_DEBUG; printk(banner); skb_queue_head_init(&tx_queue); dev_add_pack(&sppp_packet_type); return 0;}static void __exit sync_ppp_cleanup(void){ dev_remove_pack(&sppp_packet_type);}module_init(sync_ppp_init);module_exit(sync_ppp_cleanup);module_param(debug, int, 0);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -