📄 ppp.c
字号:
ppp->escape = 0; } else if (chr == PPP_ESCAPE) { ppp->escape = PPP_TRANS; continue; } /* * Allocate an skbuff on the first character received. * The 128 is room for VJ header expansion and FCS. */ if (skb == NULL) { skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN); if (skb == NULL) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "couldn't " "alloc skb for recv\n"); ppp->toss = 1; continue; } } /* * Decompress A/C and protocol compression here. */ if (skb->len == 0 && chr != PPP_ALLSTATIONS) { p = skb_put(skb, 2); p[0] = PPP_ALLSTATIONS; p[1] = PPP_UI; } if (skb->len == 2 && (chr & 1) != 0) { p = skb_put(skb, 1); p[0] = 0; } /* * Check if we've overflowed the MRU */ if (skb->len >= ppp->mru + PPP_HDRLEN + 2 || skb_tailroom(skb) <= 0) { ++ppp->estats.rx_length_errors; ppp->toss = 0xC0; if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "rcv frame too long: " "len=%d mru=%d hroom=%d troom=%d\n", skb->len, ppp->mru, skb_headroom(skb), skb_tailroom(skb)); continue; } /* * Store the character and update the FCS. */ p = skb_put(skb, 1); *p = chr; ppp->rfcs = PPP_FCS(ppp->rfcs, chr); } ppp->rpkt = skb;}/************************************************************* * PPP NETWORK INTERFACE SUPPORT * The following code implements the PPP network * interface device and handles those parts of * the PPP processing which are independent of the * type of hardware link being used, including * VJ and packet compression. *************************************************************//* * Network device driver callback routines */static int ppp_init_dev(struct device *dev);static int ppp_dev_open(struct device *);static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd);static int ppp_dev_close(struct device *);static int ppp_dev_xmit(struct sk_buff *, struct device *);static struct net_device_stats *ppp_dev_stats (struct device *);/* * Information for the protocol decoder */typedef int (*pfn_proto) (struct ppp *, struct sk_buff *);typedef struct ppp_proto_struct { int proto; pfn_proto func;} ppp_proto_type;static int rcv_proto_ip (struct ppp *, struct sk_buff *);static int rcv_proto_ipv6 (struct ppp *, struct sk_buff *);static int rcv_proto_ipx (struct ppp *, struct sk_buff *);static int rcv_proto_at (struct ppp *, struct sk_buff *);static int rcv_proto_vjc_comp (struct ppp *, struct sk_buff *);static int rcv_proto_vjc_uncomp (struct ppp *, struct sk_buff *);static int rcv_proto_ccp (struct ppp *, struct sk_buff *);static int rcv_proto_unknown (struct ppp *, struct sk_buff *);staticppp_proto_type proto_list[] = { { PPP_IP, rcv_proto_ip }, { PPP_IPV6, rcv_proto_ipv6 }, { PPP_IPX, rcv_proto_ipx }, { PPP_AT, rcv_proto_at }, { PPP_VJC_COMP, rcv_proto_vjc_comp }, { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp }, { PPP_CCP, rcv_proto_ccp }, { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */};/* * Called when the PPP network interface device is actually created. */static intppp_init_dev (struct device *dev){ dev->hard_header_len = PPP_HDRLEN; /* device INFO */ dev->mtu = PPP_MTU; dev->hard_start_xmit = ppp_dev_xmit; dev->open = ppp_dev_open; dev->stop = ppp_dev_close; dev->get_stats = ppp_dev_stats; dev->do_ioctl = ppp_dev_ioctl; dev->addr_len = 0; dev->tx_queue_len = 10; dev->type = ARPHRD_PPP; dev_init_buffers(dev); dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; return 0;}/* * Callback from the network layer when the device goes up. */static intppp_dev_open (struct device *dev){ struct ppp *ppp = dev2ppp(dev); if (!ppp->inuse || ppp2tty(ppp) == NULL) { printk(KERN_ERR "ppp: %s not active\n", dev->name); return -ENXIO; } MOD_INC_USE_COUNT; return 0;}/* * Callback from the network layer when the ppp device goes down. */static intppp_dev_close (struct device *dev){ struct ppp *ppp = dev2ppp (dev); CHECK_PPP_MAGIC(ppp); /* ppp_dev_close may be called with tbusy==1 so we must set it to 0 */ dev->tbusy=0; MOD_DEC_USE_COUNT; return 0;}static inline voidget_vj_stats(struct vjstat *vj, struct slcompress *slc){ vj->vjs_packets = slc->sls_o_compressed + slc->sls_o_uncompressed; vj->vjs_compressed = slc->sls_o_compressed; vj->vjs_searches = slc->sls_o_searches; vj->vjs_misses = slc->sls_o_misses; vj->vjs_errorin = slc->sls_i_error; vj->vjs_tossed = slc->sls_i_tossed; vj->vjs_uncompressedin = slc->sls_i_uncompressed; vj->vjs_compressedin = slc->sls_i_compressed;}/* * Callback from the network layer to process the sockioctl functions. */static intppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd){ struct ppp *ppp = dev2ppp(dev); int nb; union { struct ppp_stats stats; struct ppp_comp_stats cstats; char vers[32]; } u; CHECK_PPP_MAGIC(ppp); memset(&u, 0, sizeof(u)); switch (cmd) { case SIOCGPPPSTATS: u.stats.p = ppp->stats; if (ppp->slcomp != NULL) get_vj_stats(&u.stats.vj, ppp->slcomp); nb = sizeof(u.stats); break; case SIOCGPPPCSTATS: if (ppp->sc_xc_state != NULL) (*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state, &u.cstats.c); if (ppp->sc_rc_state != NULL) (*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state, &u.cstats.d); nb = sizeof(u.cstats); break; case SIOCGPPPVER: strcpy(u.vers, szVersion); nb = strlen(u.vers) + 1; break; default: return -EINVAL; } if (copy_to_user((void *) ifr->ifr_ifru.ifru_data, &u, nb)) return -EFAULT; return 0;}/* * Process the generic PPP ioctls, i.e. those which are not specific * to any particular type of hardware link. */static intppp_ioctl(struct ppp *ppp, unsigned int param2, unsigned long param3){ register int temp_i = 0, oldflags; int error = -EFAULT; unsigned long flags; struct ppp_idle cur_ddinfo; struct npioctl npi; CHECK_PPP(-ENXIO); /* * The user must have an euid of root to do these requests. */ if (!capable(CAP_NET_ADMIN)) return -EPERM; switch (param2) { case PPPIOCSMRU: /* * Set the MRU value */ if (get_user(temp_i, (int *) param3)) break; if (temp_i < PPP_MRU) temp_i = PPP_MRU; ppp->mru = temp_i; if (ppp->flags & SC_DEBUG) printk(KERN_INFO "ppp_ioctl: set mru to %x\n", temp_i); error = 0; break; case PPPIOCGFLAGS: /* * Fetch the current flags */ temp_i = ppp->flags & SC_MASK;#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */ temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP;#endif if (put_user(temp_i, (int *) param3)) break; error = 0; break; case PPPIOCSFLAGS: /* * Set the flags for the various options */ if (get_user(temp_i, (int *) param3)) break; if (ppp->flags & ~temp_i & SC_CCP_OPEN) ppp_ccp_closed(ppp); save_flags(flags); cli(); oldflags = ppp->flags; temp_i = (temp_i & SC_MASK) | (oldflags & ~SC_MASK); ppp->flags = temp_i; restore_flags(flags); if ((oldflags | temp_i) & SC_DEBUG) printk(KERN_INFO "ppp_ioctl: set flags to %x\n", temp_i); error = 0; break; case PPPIOCSCOMPRESS: /* * Set the compression mode */ error = ppp_set_compression (ppp, (struct ppp_option_data *) param3); break; case PPPIOCGUNIT: /* * Obtain the unit number for this device. */ if (put_user(ppp->line, (int *) param3)) break; if (ppp->flags & SC_DEBUG) printk(KERN_INFO "ppp_ioctl: get unit: %d\n", ppp->line); error = 0; break; case PPPIOCSDEBUG: /* * Set the debug level */ if (get_user(temp_i, (int *) param3)) break; temp_i = (temp_i & 0x1F) << 16; if ((ppp->flags | temp_i) & SC_DEBUG) printk(KERN_INFO "ppp_ioctl: set dbg flags to %x\n", temp_i); save_flags(flags); cli(); ppp->flags = (ppp->flags & ~0x1F0000) | temp_i; restore_flags(flags); error = 0; break; case PPPIOCGDEBUG: /* * Get the debug level */ temp_i = (ppp->flags >> 16) & 0x1F; if (put_user(temp_i, (int *) param3)) break; error = 0; break; case PPPIOCGIDLE: /* * Get the times since the last send/receive frame operation */ /* change absolute times to relative times. */ cur_ddinfo.xmit_idle = (jiffies - ppp->last_xmit) / HZ; cur_ddinfo.recv_idle = (jiffies - ppp->last_recv) / HZ; if (copy_to_user((void *) param3, &cur_ddinfo, sizeof (cur_ddinfo))) break; error = 0; break; case PPPIOCSMAXCID: /* * Set the maximum VJ header compression slot number. */ if (get_user(temp_i, (int *) param3)) break; error = -EINVAL; if (temp_i < 2 || temp_i > 255) break; ++temp_i; if (ppp->flags & SC_DEBUG) printk(KERN_INFO "ppp_ioctl: set maxcid to %d\n", temp_i); if (ppp->slcomp != NULL) slhc_free(ppp->slcomp); ppp->slcomp = slhc_init(16, temp_i); error = -ENOMEM; if (ppp->slcomp == NULL) { printk(KERN_ERR "ppp: no memory for VJ compression\n"); break; } error = 0; break; case PPPIOCGNPMODE: case PPPIOCSNPMODE: if (copy_from_user(&npi, (void *) param3, sizeof(npi))) break; switch (npi.protocol) { case PPP_IP: npi.protocol = NP_IP; break; case PPP_IPX: npi.protocol = NP_IPX; break; case PPP_AT: npi.protocol = NP_AT; break; default: if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "pppioc[gs]npmode: " "invalid proto %d\n", npi.protocol); error = -EINVAL; goto out; } if (param2 == PPPIOCGNPMODE) { npi.mode = ppp->sc_npmode[npi.protocol]; if (copy_to_user((void *) param3, &npi, sizeof(npi))) break; } else { ppp->sc_npmode[npi.protocol] = npi.mode; if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "ppp: set np %d to %d\n", npi.protocol, npi.mode); mark_bh(NET_BH); } error = 0; break; default: /* * All other ioctl() events will come here. */ if (ppp->flags & SC_DEBUG) printk(KERN_ERR "ppp_ioctl: invalid ioctl: %x, addr %lx\n", param2, param3); error = -ENOIOCTLCMD; break; }out: return error;}/* * Process the set-compression ioctl. */static intppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp){ struct compressor *cp; int error, nb; unsigned long flags; __u8 *ptr; __u8 ccp_option[CCP_MAX_OPTION_LENGTH]; struct ppp_option_data data; /* * Fetch the compression parameters */ error = -EFAULT; if (copy_from_user(&data, odp, sizeof (data))) goto out; nb = data.length; ptr = data.ptr; if ((unsigned) nb >= CCP_MAX_OPTION_LENGTH) nb = CCP_MAX_OPTION_LENGTH; if (copy_from_user(ccp_option, ptr, nb)) goto out; error = -EINVAL; if (ccp_option[1] < 2) /* preliminary check on the length byte */ goto out; save_flags(flags); cli(); ppp->flags &= ~(data.transmit? SC_COMP_RUN: SC_DECOMP_RUN); restore_flags(flags); cp = find_compressor (ccp_option[0]);#ifdef CONFIG_KMOD if (cp == NULL) { char modname[32]; sprintf(modname, "ppp-compress-%d", ccp_option[0]); request_module(modname); cp = find_compressor(ccp_option[0]); }#endif /* CONFIG_KMOD */ if (cp == NULL) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: no compressor for [%x %x %x], %x\n", ppp->name, ccp_option[0], ccp_option[1], ccp_option[2], nb); goto out; /* compressor not loaded */ } /* * Found a handler for the protocol - try to allocate * a compressor or decompressor. */ error = 0; if (data.transmit) { if (ppp->sc_xc_state != NULL) (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); ppp->sc_xc_state = NULL; ppp->sc_xcomp = cp; ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb); if (ppp->sc_xc_state == NULL) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: comp_alloc failed\n", ppp->name); error = -ENOBUFS; } } else { if (ppp->sc_rc_state != NULL) (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state); ppp->sc_rc_state = NULL; ppp->sc_rcomp = cp; ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb); if (ppp->sc_rc_state == NULL) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: decomp_alloc failed\n", ppp->name); error = -ENOBUFS; } }out: return error;}/* * Handle a CCP packet. * * The CCP packet is passed along to the pppd process just like any * other PPP frame. The difference is that some processing needs to be * immediate or the compressors will become confused on the peer. */static void ppp_proto_ccp(struct ppp *ppp, __u8 *dp, int len, int rcvd){ int slen = CCP_LENGTH(dp); __u8 *opt = dp + CCP_HDRLEN; int opt_len = slen - CCP_HDRLEN; unsigned long flags; if (slen > len) return; if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "ppp_proto_ccp rcvd=%d code=%x flags=%x\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -