📄 syncppp.c
字号:
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_LCP, LCP_CODE_REJ, ++sp->pp_seq, skb->len, h); break; case LCP_CONF_REQ: if (len < 4) { if (sp->pp_flags & PP_DEBUG) printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n", dev->name, 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) { printk (KERN_WARNING "%s: loopback\n", dev->name); sp->pp_loopcnt = 0; if (dev->flags & IFF_UP) { if_down (dev); } } else if (sp->pp_flags & PP_DEBUG) printk (KERN_DEBUG "%s: conf req: magic glitch\n", dev->name); ++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; if (sp->lcp.state != LCP_STATE_OPENED) { 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); /* Send ACK after our REQ in attempt to break loop */ sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, h->ident, len-4, h+1); sp->lcp.state = LCP_STATE_ACK_SENT; break; } break; case LCP_CONF_ACK: if (h->ident != sp->lcp.confid) break; sppp_clear_timeout (sp); if ((sp->pp_link_state != SPPP_LINK_UP) && (dev->flags & IFF_UP)) { /* Coming out of loopback mode. */ sp->pp_link_state=SPPP_LINK_UP; printk (KERN_INFO "%s: protocol up\n", dev->name); } switch (sp->lcp.state) { case LCP_STATE_CLOSED: sp->lcp.state = LCP_STATE_ACK_RCVD; sppp_set_timeout (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 = (u8*) (h+1); if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { rmagic = (u32)p[2] << 24 | (u32)p[3] << 16 | p[4] << 8 | p[5]; if (rmagic == ~sp->lcp.magic) { int newmagic; if (sp->pp_flags & PP_DEBUG) printk (KERN_DEBUG "%s: conf nak: magic glitch\n", dev->name); get_random_bytes(&newmagic, sizeof(newmagic)); sp->lcp.magic += newmagic; } 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. */ sppp_clear_timeout (sp); sppp_set_timeout (sp, 2); break; case LCP_CONF_REJ: if (h->ident != sp->lcp.confid) break; sppp_clear_timeout (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: sppp_clear_timeout (sp); /* Send Terminate-Ack packet. */ sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, NULL); /* 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 (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n", dev->name, len); break; } if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { /* Line loopback mode detected. */ printk (KERN_WARNING "%s: loopback\n", dev->name); if_down (dev); /* Shut down the PPP link. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sppp_clear_timeout (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 (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n", dev->name, len); break; } if (ntohl (*(long*)(h+1)) != sp->lcp.magic) sp->pp_alivecnt = 0; break; }}/* * Handle incoming Cisco keepalive protocol packets. */static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb){ struct cisco_packet *h; struct net_device *dev = sp->pp_if; if (!pskb_may_pull(skb, sizeof(struct cisco_packet)) || (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN)) { if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n", dev->name, skb->len); return; } h = (struct cisco_packet *)skb->data; skb_pull(skb, sizeof(struct cisco_packet*)); if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n", dev->name, skb->len, ntohl (h->type), h->par1, h->par2, h->rel, h->time0, h->time1); switch (ntohl (h->type)) { default: if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: unknown cisco packet type: 0x%x\n", dev->name, 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. */ int newseq; if (sp->pp_loopcnt >= MAXALIVECNT) { printk (KERN_WARNING "%s: loopback\n", dev->name); sp->pp_loopcnt = 0; if (dev->flags & IFF_UP) { if_down (dev); } } ++sp->pp_loopcnt; /* Generate new local sequence number */ get_random_bytes(&newseq, sizeof(newseq)); sp->pp_seq ^= newseq; break; } sp->pp_loopcnt = 0; if (sp->pp_link_state==SPPP_LINK_DOWN && (dev->flags & IFF_UP)) { sp->pp_link_state=SPPP_LINK_UP; printk (KERN_INFO "%s: protocol up\n", dev->name); } break; case CISCO_ADDR_REQ: /* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */ { struct in_device *in_dev; struct in_ifaddr *ifa; u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */#ifdef CONFIG_INET rcu_read_lock(); if ((in_dev = __in_dev_get_rcu(dev)) != NULL) { for (ifa=in_dev->ifa_list; ifa != NULL; ifa=ifa->ifa_next) { if (strcmp(dev->name, ifa->ifa_label) == 0) { addr = ifa->ifa_local; mask = ifa->ifa_mask; break; } } } rcu_read_unlock();#endif /* I hope both addr and mask are in the net order */ sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask); break; } }}/* * Send PPP LCP packet. */static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, u8 ident, u16 len, void *data){ struct ppp_header *h; struct lcp_header *lh; struct sk_buff *skb; struct net_device *dev = sp->pp_if; skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len, GFP_ATOMIC); if (skb==NULL) return; skb_reserve(skb,dev->hard_header_len); h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header)); h->address = PPP_ALLSTATIONS; /* broadcast address */ h->control = PPP_UI; /* Unnumbered Info */ h->protocol = htons (proto); /* Link Control Protocol */ lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header)); lh->type = type; lh->ident = ident; lh->len = htons (LCP_HEADER_LEN + len); if (len) memcpy(skb_put(skb,len),data, len); if (sp->pp_flags & PP_DEBUG) { printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh", dev->name, proto==PPP_LCP ? "lcp" : "ipcp", proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : sppp_ipcp_type_name (lh->type), lh->ident, ntohs (lh->len)); if (len) sppp_print_bytes ((u8*) (lh+1), len); printk (">\n"); } sp->obytes += skb->len; /* Control is high priority so it doesn't get queued behind data */ skb->priority=TC_PRIO_CONTROL; skb->dev = dev; skb_queue_tail(&tx_queue, skb);}/* * Send Cisco keepalive packet. */static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2){ struct ppp_header *h; struct cisco_packet *ch; struct sk_buff *skb; struct net_device *dev = sp->pp_if; u32 t = jiffies * 1000/HZ; skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN, GFP_ATOMIC); if(skb==NULL) return; skb_reserve(skb, dev->hard_header_len); h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header)); h->address = CISCO_MULTICAST; h->control = 0; h->protocol = htons (CISCO_KEEPALIVE); ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN); ch->type = htonl (type); ch->par1 = htonl (par1); ch->par2 = htonl (par2); ch->rel = -1; ch->time0 = htons ((u16) (t >> 16)); ch->time1 = htons ((u16) t); if (sp->pp_flags & PP_DEBUG) printk (KERN_WARNING "%s: cisco output: <%xh %xh %xh %xh %xh-%xh>\n", dev->name, ntohl (ch->type), ch->par1, ch->par2, ch->rel, ch->time0, ch->time1); sp->obytes += skb->len; skb->priority=TC_PRIO_CONTROL; skb->dev = dev; skb_queue_tail(&tx_queue, skb);}/** * sppp_close - close down a synchronous PPP or Cisco HDLC link * @dev: The network device to drop the link of * * This drops the logical interface to the channel. It is not * done politely as we assume we will also be dropping DTR. Any * timeouts are killed. */int sppp_close (struct net_device *dev){ struct sppp *sp = (struct sppp *)sppp_of(dev); unsigned long flags; spin_lock_irqsave(&sp->lock, flags); sp->pp_link_state = SPPP_LINK_DOWN; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sppp_clear_timeout (sp); spin_unlock_irqrestore(&sp->lock, flags); return 0;}EXPORT_SYMBOL(sppp_close);/** * sppp_open - open a synchronous PPP or Cisco HDLC link * @dev: Network device to activate * * Close down any existing synchronous session and commence * from scratch. In the PPP case this means negotiating LCP/IPCP * and friends, while for Cisco HDLC we simply need to start sending * keepalives */int sppp_open (struct net_device *dev){ struct sppp *sp = (struct sppp *)sppp_of(dev); unsigned long flags; sppp_close(dev); spin_lock_irqsave(&sp->lock, flags); if (!(sp->pp_flags & PP_CISCO)) { sppp_lcp_open (sp); } sp->pp_link_state = SPPP_LINK_DOWN; spin_unlock_irqrestore(&sp->lock, flags); sppp_flush_xmit(); return 0;}EXPORT_SYMBOL(sppp_open);/** * sppp_reopen - notify of physical link loss * @dev: Device that lost the link * * This function informs the synchronous protocol code that * the underlying link died (for example a carrier drop on X.21) * * We increment the magic numbers to ensure that if the other end * failed to notice we will correctly start a new session. It happens * do to the nature of telco circuits is that you can lose carrier on * one endonly. * * Having done this we go back to negotiating. This function may * be called from an interrupt context. */ int sppp_reopen (struct net_device *dev){ struct sppp *sp = (struct sppp *)sppp_of(dev); unsigned long flags; sppp_close(dev); spin_lock_irqsave(&sp->lock, flags); if (!(sp->pp_flags & PP_CISCO)) { sp->lcp.magic = jiffies; ++sp->pp_seq; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; /* Give it a moment for the line to settle then go */ sppp_set_timeout (sp, 1); } sp->pp_link_state=SPPP_LINK_DOWN; spin_unlock_irqrestore(&sp->lock, flags); return 0;}EXPORT_SYMBOL(sppp_reopen);/** * sppp_change_mtu - Change the link MTU * @dev: Device to change MTU on * @new_mtu: New MTU * * Change the MTU on the link. This can only be called with * the link down. It returns an error if the link is up or * the mtu is out of range. */ static int sppp_change_mtu(struct net_device *dev, int new_mtu){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -