📄 ppp.c
字号:
__u8 *orig_data, *data; struct sk_buff *new_skb; int len, proto; new_skb = alloc_skb(skb->len, GFP_ATOMIC); if (new_skb == NULL) { printk(KERN_ERR "ppp: no memory for vj compression\n"); return skb; } orig_data = data = skb->data + PPP_HDRLEN; len = slhc_compress(ppp->slcomp, data, skb->len - PPP_HDRLEN, new_skb->data + PPP_HDRLEN, &data, (ppp->flags & SC_NO_TCP_CCID) == 0); if (data == orig_data) { /* Couldn't compress the data */ kfree_skb(new_skb); return skb; } /* The data has been changed */ if (data[0] & SL_TYPE_COMPRESSED_TCP) { proto = PPP_VJC_COMP; data[0] ^= SL_TYPE_COMPRESSED_TCP; } else { if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP) proto = PPP_VJC_UNCOMP; else proto = PPP_IP; data[0] = orig_data[0]; } data = skb_put(new_skb, len + PPP_HDRLEN); data[0] = PPP_ALLSTATIONS; data[1] = PPP_UI; data[2] = 0; data[3] = proto; kfree_skb(skb); return new_skb;}static inline voidppp_send_frames(struct ppp *ppp){ struct sk_buff *skb; while (!test_and_set_bit(0, &ppp->xmit_busy)) { skb = skb_dequeue(&ppp->xmt_q); if (skb == NULL) { ppp->xmit_busy = 0; break; } ppp_send_frame(ppp, skb); } if (!ppp->xmit_busy && ppp->dev.tbusy) { ppp->dev.tbusy = 0; mark_bh(NET_BH); }}/* * Called from the hardware (tty) layer when it can accept * another packet. */static voidppp_output_wakeup(struct ppp *ppp){ CHECK_PPP_VOID(); if (!ppp->xmit_busy) { printk(KERN_ERR "ppp_output_wakeup called but xmit_busy==0\n"); return; } ppp->xmit_busy = 0; ppp_send_frames(ppp);}/* * Send a control frame (from pppd). */static voidppp_send_ctrl(struct ppp *ppp, struct sk_buff *skb){ CHECK_PPP_VOID(); /* * Put the packet on the queue, then send as many as we can. */ skb_queue_tail(&ppp->xmt_q, skb); ppp_send_frames(ppp);}/************************************************************* * NETWORK OUTPUT * This routine accepts requests from the network layer * and attempts to deliver the packets. *************************************************************//* * Send a frame to the peer. * Returns 1 iff the frame was not accepted. */static intppp_dev_xmit(struct sk_buff *skb, struct device *dev){ struct ppp *ppp = dev2ppp(dev); struct tty_struct *tty = ppp2tty(ppp); enum NPmode npmode; int proto; unsigned char *hdr; /* just a little sanity check. */ if (skb == NULL) return 0; if (skb->data == NULL) { kfree_skb(skb); return 0; } /* * Avoid timing problem should tty hangup while data is * queued to be sent. */ if (!ppp->inuse) { dev_kfree_skb(skb); return 0; } /* * Validate the tty interface */ if (tty == NULL) { if (ppp->flags & SC_DEBUG) printk(KERN_ERR "ppp_dev_xmit: %s not connected to a TTY!\n", dev->name); dev_kfree_skb(skb); return 0; } /* * Work out the appropriate network-protocol mode for this packet. */ npmode = NPMODE_PASS; /* default */ switch (ntohs(skb->protocol)) { case ETH_P_IP: proto = PPP_IP; npmode = ppp->sc_npmode[NP_IP]; break; case ETH_P_IPV6: proto = PPP_IPV6; npmode = ppp->sc_npmode[NP_IPV6]; break; case ETH_P_IPX: proto = PPP_IPX; npmode = ppp->sc_npmode[NP_IPX]; break; case ETH_P_PPPTALK: case ETH_P_ATALK: proto = PPP_AT; npmode = ppp->sc_npmode[NP_AT]; break; default: if (ppp->flags & SC_DEBUG) printk(KERN_INFO "%s: packet for unknown proto %x\n", ppp->name, ntohs(skb->protocol)); dev_kfree_skb(skb); return 0; } /* * Drop, accept or reject the packet depending on the mode. */ switch (npmode) { case NPMODE_PASS: break; case NPMODE_QUEUE: /* * We may not send the packet now, so drop it. * XXX It would be nice to be able to return it to the * network system to be queued and retransmitted later. */ if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: returning frame\n", ppp->name); dev_kfree_skb(skb); return 0; case NPMODE_ERROR: case NPMODE_DROP: if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "ppp_dev_xmit: dropping (npmode = %d) on %s\n", npmode, ppp->name); dev_kfree_skb(skb); return 0; } /* * The dev->tbusy field acts as a lock to allow only * one packet to be processed at a time. If we can't * get the lock, try again later. * We deliberately queue as little as possible inside * the ppp driver in order to minimize the latency * for high-priority packets. */ if (test_and_set_bit(0, &ppp->xmit_busy)) { dev->tbusy = 1; /* can't take it now */ return 1; } dev->tbusy = 0; /* * Put the 4-byte PPP header on the packet. * If there isn't room for it, we have to copy the packet. */ if (skb_headroom(skb) < PPP_HDRLEN) { struct sk_buff *new_skb; new_skb = alloc_skb(skb->len + PPP_HDRLEN, GFP_ATOMIC); if (new_skb == NULL) { printk(KERN_ERR "%s: skb hdr alloc failed\n", ppp->name); dev_kfree_skb(skb); ppp->xmit_busy = 0; ppp_send_frames(ppp); return 0; } skb_reserve(new_skb, PPP_HDRLEN); memcpy(skb_put(new_skb, skb->len), skb->data, skb->len); dev_kfree_skb(skb); skb = new_skb; } hdr = skb_push(skb, PPP_HDRLEN); hdr[0] = PPP_ALLSTATIONS; hdr[1] = PPP_UI; hdr[2] = proto >> 8; hdr[3] = proto; ppp_send_frame(ppp, skb); if (!ppp->xmit_busy) ppp_send_frames(ppp); return 0;}/* * Generate the statistic information for the /proc/net/dev listing. */static struct net_device_stats *ppp_dev_stats (struct device *dev){ struct ppp *ppp = dev2ppp (dev); ppp->estats.rx_packets = ppp->stats.ppp_ipackets; ppp->estats.rx_errors = ppp->stats.ppp_ierrors; ppp->estats.tx_packets = ppp->stats.ppp_opackets; ppp->estats.tx_errors = ppp->stats.ppp_oerrors; ppp->estats.rx_bytes = ppp->stats.ppp_ibytes; ppp->estats.tx_bytes = ppp->stats.ppp_obytes; return &ppp->estats;}/************************************************************* * UTILITIES * Miscellany called by various functions above. *************************************************************//* Locate the previous instance of the PPP channel */static struct ppp *ppp_find(int pid_value){ struct ppp *ppp; /* try to find the device which this pid is already using */ for (ppp = ppp_list; ppp != 0; ppp = ppp->next) { if (ppp->inuse && ppp->sc_xfer == pid_value) { ppp->sc_xfer = 0; break; } } return ppp;}/* allocate or create a PPP channel */static struct ppp *ppp_alloc(void){ int if_num; int status; struct device *dev; struct ppp *ppp; /* try to find an free device */ for (ppp = ppp_list; ppp != 0; ppp = ppp->next) { if (!test_and_set_bit(0, &ppp->inuse)) { dev = ppp2dev(ppp); if (dev->flags & IFF_UP) { clear_bit(0, &ppp->inuse); continue; } /* Reregister device */ unregister_netdev(dev); if (register_netdev(dev) == 0) return ppp; printk(KERN_DEBUG "could not reregister ppp device\n"); /* leave inuse set in this case */ } } /* * There are no available units, so make a new one. */ ppp = (struct ppp *) kmalloc(sizeof(struct ppp), GFP_KERNEL); if (ppp == 0) { printk(KERN_ERR "ppp: struct ppp allocation failed\n"); return 0; } memset(ppp, 0, sizeof(*ppp)); /* initialize channel control data */ ppp->magic = PPP_MAGIC; ppp->next = NULL; ppp->inuse = 1; ppp->read_wait = NULL; /* * Make up a suitable name for this device */ dev = ppp2dev(ppp); dev->name = ppp->name; if_num = dev_alloc_name(dev, "ppp%d"); if (if_num < 0) { printk(KERN_ERR "ppp: dev_alloc_name failed (%d)\n", if_num); kfree(ppp); return 0; } ppp->line = if_num; ppp->slcomp = NULL; dev->next = NULL; dev->init = ppp_init_dev; dev->name = ppp->name; dev->priv = (void *) ppp; /* register device so that we can be ifconfig'd */ /* ppp_init_dev() will be called as a side-effect */ status = register_netdev (dev); if (status == 0) { printk(KERN_INFO "registered device %s\n", dev->name); } else { printk(KERN_ERR "ppp_alloc - register_netdev(%s) = %d failure.\n", dev->name, status); kfree(ppp); ppp = NULL; } /* link this unit into our list */ if (ppp_list == 0) ppp_list = ppp; else ppp_last->next = ppp; ppp_last = ppp; return ppp;}/* * Initialize the generic parts of the ppp structure. */static voidppp_generic_init(struct ppp *ppp){ int indx; ppp->flags = 0; ppp->mtu = PPP_MTU; ppp->mru = PPP_MRU; skb_queue_head_init(&ppp->xmt_q); skb_queue_head_init(&ppp->rcv_q); ppp->last_xmit = jiffies; ppp->last_recv = jiffies; ppp->xmit_busy = 0; /* clear statistics */ memset(&ppp->stats, 0, sizeof (struct pppstat)); memset(&ppp->estats, 0, sizeof(struct net_device_stats)); /* PPP compression data */ ppp->sc_xc_state = NULL; ppp->sc_rc_state = NULL; for (indx = 0; indx < NUM_NP; ++indx) ppp->sc_npmode[indx] = NPMODE_PASS;}/* * Called to clean up the generic parts of the ppp structure. */static voidppp_release(struct ppp *ppp){ struct sk_buff *skb; CHECK_PPP_MAGIC(ppp); if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s released\n", ppp->name); ppp_ccp_closed(ppp); /* Ensure that the pppd process is not hanging on select()/poll() */ wake_up_interruptible(&ppp->read_wait); if (ppp->slcomp) { slhc_free(ppp->slcomp); ppp->slcomp = NULL; } while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL) kfree_skb(skb); while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL) kfree_skb(skb); ppp->inuse = 0; if (ppp->dev.tbusy) { ppp->dev.tbusy = 0; mark_bh(NET_BH); }}/* * Utility procedures to print a buffer in hex/ascii */static voidppp_print_hex (register __u8 * out, const __u8 * in, int count){ register __u8 next_ch; static char hex[] = "0123456789ABCDEF"; while (count-- > 0) { next_ch = *in++; *out++ = hex[(next_ch >> 4) & 0x0F]; *out++ = hex[next_ch & 0x0F]; ++out; }}static voidppp_print_char (register __u8 * out, const __u8 * in, int count){ register __u8 next_ch; while (count-- > 0) { next_ch = *in++; if (next_ch < 0x20 || next_ch > 0x7e) *out++ = '.'; else { *out++ = next_ch; if (next_ch == '%') /* printk/syslogd has a bug !! */ *out++ = '%'; } } *out = '\0';}static voidppp_print_buffer (const char *name, const __u8 *buf, int count){ __u8 line[44]; if (name != NULL) printk(KERN_DEBUG "ppp: %s, count = %d\n", name, count); while (count > 8) { memset (line, 32, 44); ppp_print_hex (line, buf, 8); ppp_print_char (&line[8 * 3], buf, 8); printk(KERN_DEBUG "%s\n", line); count -= 8; buf += 8; } if (count > 0) { memset (line, 32, 44); ppp_print_hex (line, buf, count); ppp_print_char (&line[8 * 3], buf, count); printk(KERN_DEBUG "%s\n", line); }}/************************************************************* * Compressor module interface *************************************************************/struct compressor_link { struct compressor_link *next; struct compressor *comp;};static struct compressor_link *ppp_compressors = (struct compressor_link *) 0;static struct compressor *find_compressor (int type){ struct compressor_link *lnk; unsigned long flags; save_flags(flags); cli(); lnk = ppp_compressors; while (lnk != (struct compressor_link *) 0) { if ((int) (__u8) lnk->comp->compress_proto == type) { restore_flags(flags); return lnk->comp; } lnk = lnk->next; } restore_flags(flags); return (struct compressor *) 0;}#ifdef CONFIG_MODULESstatic int ppp_register_compressor (struct compressor *cp){ struct compressor_link *new; unsigned long flags; new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL); if (new == (struct compressor_link *) 0) return 1; save_flags(flags); cli(); if (find_compressor (cp->compress_proto)) { restore_flags(flags); kfree (new); return 0; } new->next = ppp_compressors; new->comp = cp; ppp_compressors = new; restore_flags(flags); return 0;}static void ppp_unregister_compressor (struct compressor *cp){ struct compressor_link *prev = (struct compressor_link *) 0; struct compressor_lin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -