⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isdn_ppp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#include <linux/config.h>#include <linux/isdn.h>#include <linux/poll.h>#include <linux/ppp-comp.h>#ifdef CONFIG_IPPP_FILTER#include <linux/filter.h>#endif#include "isdn_common.h"#include "isdn_ppp.h"#include "isdn_net.h"#ifndef PPP_IPX#define PPP_IPX 0x002b#endif/* Prototypes */static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);static int isdn_ppp_closewait(int slot);static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,				 struct sk_buff *skb, int proto);static int isdn_ppp_if_get_unit(char *namebuf);static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *);static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,				struct ippp_struct *,struct ippp_struct *,int *proto);static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,				struct sk_buff *skb,int proto);static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,	struct ippp_struct *is,struct ippp_struct *master,int type);static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,	 struct sk_buff *skb);/* New CCP stuff */static void isdn_ppp_ccp_kickup(struct ippp_struct *is);static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,				    unsigned char code, unsigned char id,				    unsigned char *data, int len);static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);static void isdn_ppp_ccp_reset_free(struct ippp_struct *is);static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,					  unsigned char id);static void isdn_ppp_ccp_timer_callback(unsigned long closure);static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,						      unsigned char id);static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,				     struct isdn_ppp_resetparams *rp);static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,					unsigned char id);#ifdef CONFIG_ISDN_MPPstatic ippp_bundle * isdn_ppp_bundle_arr = NULL; static int isdn_ppp_mp_bundle_array_init(void);static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to );static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, 							struct sk_buff *skb);static void isdn_ppp_mp_cleanup( isdn_net_local * lp );static int isdn_ppp_bundle(struct ippp_struct *, int unit);#endif	/* CONFIG_ISDN_MPP */  char *isdn_ppp_revision = "$Revision: 1.1.2.3 $";static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];static struct isdn_ppp_compressor *ipc_head = NULL;/* * frame log (debug) */static voidisdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot){	int cnt,	 j,	 i;	char buf[80];	if (len < maxlen)		maxlen = len;	for (i = 0, cnt = 0; cnt < maxlen; i++) {		for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)			sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);		printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf);	}}/* * unbind isdn_net_local <=> ippp-device * note: it can happen, that we hangup/free the master before the slaves *       in this case we bind another lp to the master device */intisdn_ppp_free(isdn_net_local * lp){	struct ippp_struct *is;	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",			__FUNCTION__, lp->ppp_slot);		return 0;	}#ifdef CONFIG_ISDN_MPP	spin_lock(&lp->netdev->pb->lock);#endif	isdn_net_rm_from_bundle(lp);#ifdef CONFIG_ISDN_MPP	if (lp->netdev->pb->ref_ct == 1)	/* last link in queue? */		isdn_ppp_mp_cleanup(lp);	lp->netdev->pb->ref_ct--;	spin_unlock(&lp->netdev->pb->lock);#endif /* CONFIG_ISDN_MPP */	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {		printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",			__FUNCTION__, lp->ppp_slot);		return 0;	}	is = ippp_table[lp->ppp_slot];	if ((is->state & IPPP_CONNECT))		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */	else if (is->state & IPPP_ASSIGNED)		is->state = IPPP_OPEN;	/* fallback to 'OPEN but not ASSIGNED' state */	if (is->debug & 0x1)		printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);	is->lp = NULL;          /* link is down .. set lp to NULL */	lp->ppp_slot = -1;      /* is this OK ?? */	return 0;}/* * bind isdn_net_local <=> ippp-device * * This function is allways called with holding dev->lock so * no additional lock is needed */intisdn_ppp_bind(isdn_net_local * lp){	int i;	int unit = 0;	struct ippp_struct *is;	int retval;	if (lp->pppbind < 0) {  /* device bounded to ippp device ? */		isdn_net_dev *net_dev = dev->netdev;		char exclusive[ISDN_MAX_CHANNELS];	/* exclusive flags */		memset(exclusive, 0, ISDN_MAX_CHANNELS);		while (net_dev) {	/* step through net devices to find exclusive minors */			isdn_net_local *lp = net_dev->local;			if (lp->pppbind >= 0)				exclusive[lp->pppbind] = 1;			net_dev = net_dev->next;		}		/*		 * search a free device / slot		 */		for (i = 0; i < ISDN_MAX_CHANNELS; i++) {			if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) {	/* OPEN, but not connected! */				break;			}		}	} else {		for (i = 0; i < ISDN_MAX_CHANNELS; i++) {			if (ippp_table[i]->minor == lp->pppbind &&			    (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)				break;		}	}	if (i >= ISDN_MAX_CHANNELS) {		printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");		retval = -1;		goto out;	}	unit = isdn_ppp_if_get_unit(lp->name);	/* get unit number from interface name .. ugly! */	if (unit < 0) {		printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);		retval = -1;		goto out;	}		lp->ppp_slot = i;	is = ippp_table[i];	is->lp = lp;	is->unit = unit;	is->state = IPPP_OPEN | IPPP_ASSIGNED;	/* assigned to a netdevice but not connected */#ifdef CONFIG_ISDN_MPP	retval = isdn_ppp_mp_init(lp, NULL);	if (retval < 0)		goto out;#endif /* CONFIG_ISDN_MPP */	retval = lp->ppp_slot; out:	return retval;}/* * kick the ipppd on the device * (wakes up daemon after B-channel connect) */voidisdn_ppp_wakeup_daemon(isdn_net_local * lp){	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",			__FUNCTION__, lp->ppp_slot);		return;	}	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;	wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);}/* * there was a hangup on the netdevice * force wakeup of the ippp device * go into 'device waits for release' state */static intisdn_ppp_closewait(int slot){	struct ippp_struct *is;	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {		printk(KERN_ERR "%s: slot(%d) out of range\n",			__FUNCTION__, slot);		return 0;	}	is = ippp_table[slot];	if (is->state)		wake_up_interruptible(&is->wq);	is->state = IPPP_CLOSEWAIT;	return 1;}/* * isdn_ppp_find_slot / isdn_ppp_free_slot */static intisdn_ppp_get_slot(void){	int i;	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {		if (!ippp_table[i]->state)			return i;	}	return -1;}/* * isdn_ppp_open */intisdn_ppp_open(int min, struct file *file){	int slot;	struct ippp_struct *is;	if (min < 0 || min > ISDN_MAX_CHANNELS)		return -ENODEV;	slot = isdn_ppp_get_slot();	if (slot < 0) {		return -EBUSY;	}	is = file->private_data = ippp_table[slot];		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",	       slot, min, is->state);	/* compression stuff */	is->link_compressor   = is->compressor = NULL;	is->link_decompressor = is->decompressor = NULL;	is->link_comp_stat    = is->comp_stat = NULL;	is->link_decomp_stat  = is->decomp_stat = NULL;	is->compflags = 0;	is->reset = isdn_ppp_ccp_reset_alloc(is);	is->lp = NULL;	is->mp_seqno = 0;       /* MP sequence number */	is->pppcfg = 0;         /* ppp configuration */	is->mpppcfg = 0;        /* mppp configuration */	is->last_link_seqno = -1;	/* MP: maybe set to Bundle-MIN, when joining a bundle ?? */	is->unit = -1;          /* set, when we have our interface */	is->mru = 1524;         /* MRU, default 1524 */	is->maxcid = 16;        /* VJ: maxcid */	is->tk = current;	init_waitqueue_head(&is->wq);	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */	is->last = is->rq;	is->minor = min;#ifdef CONFIG_ISDN_PPP_VJ	/*	 * VJ header compression init	 */	is->slcomp = slhc_init(16, 16);	/* not necessary for 2. link in bundle */#endif#ifdef CONFIG_IPPP_FILTER	is->pass_filter = NULL;	is->active_filter = NULL;#endif	is->state = IPPP_OPEN;	return 0;}/* * release ippp device */voidisdn_ppp_release(int min, struct file *file){	int i;	struct ippp_struct *is;	if (min < 0 || min >= ISDN_MAX_CHANNELS)		return;	is = file->private_data;	if (!is) {		printk(KERN_ERR "%s: no file->private_data\n", __FUNCTION__);		return;	}	if (is->debug & 0x1)		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);	if (is->lp) {           /* a lp address says: this link is still up */		isdn_net_dev *p = is->lp->netdev;		if (!p) {			printk(KERN_ERR "%s: no lp->netdev\n", __FUNCTION__);			return;		}		is->state &= ~IPPP_CONNECT;	/* -> effect: no call of wakeup */		/*		 * isdn_net_hangup() calls isdn_ppp_free()		 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1		 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()		 */		isdn_net_hangup(&p->dev);	}	for (i = 0; i < NUM_RCV_BUFFS; i++) {		kfree(is->rq[i].buf);		is->rq[i].buf = NULL;	}	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */	is->last = is->rq;#ifdef CONFIG_ISDN_PPP_VJ/* TODO: if this was the previous master: link the slcomp to the new master */	slhc_free(is->slcomp);	is->slcomp = NULL;#endif#ifdef CONFIG_IPPP_FILTER	kfree(is->pass_filter);	is->pass_filter = NULL;	kfree(is->active_filter);	is->active_filter = NULL;#endif/* TODO: if this was the previous master: link the stuff to the new master */	if(is->comp_stat)		is->compressor->free(is->comp_stat);	if(is->link_comp_stat)		is->link_compressor->free(is->link_comp_stat);	if(is->link_decomp_stat)		is->link_decompressor->free(is->link_decomp_stat);	if(is->decomp_stat)		is->decompressor->free(is->decomp_stat);        is->compressor   = is->link_compressor   = NULL;        is->decompressor = is->link_decompressor = NULL;	is->comp_stat    = is->link_comp_stat    = NULL;        is->decomp_stat  = is->link_decomp_stat  = NULL;	/* Clean up if necessary */	if(is->reset)		isdn_ppp_ccp_reset_free(is);	/* this slot is ready for new connections */	is->state = 0;}/* * get_arg .. ioctl helper */static intget_arg(void __user *b, void *val, int len){	if (len <= 0)		len = sizeof(void *);	if (copy_from_user(val, b, len))		return -EFAULT;	return 0;}/* * set arg .. ioctl helper */static intset_arg(void __user *b, void *val,int len){	if(len <= 0)		len = sizeof(void *);	if (copy_to_user(b, val, len))		return -EFAULT;	return 0;}static int get_filter(void __user *arg, struct sock_filter **p){	struct sock_fprog uprog;	struct sock_filter *code = NULL;	int len, err;	if (copy_from_user(&uprog, arg, sizeof(uprog)))		return -EFAULT;	if (!uprog.len) {		*p = NULL;		return 0;	}	/* uprog.len is unsigned short, so no overflow here */	len = uprog.len * sizeof(struct sock_filter);	code = kmalloc(len, GFP_KERNEL);	if (code == NULL)		return -ENOMEM;	if (copy_from_user(code, uprog.filter, len)) {		kfree(code);		return -EFAULT;	}	err = sk_chk_filter(code, uprog.len);	if (err) {		kfree(code);		return err;	}	*p = code;	return uprog.len;}/* * ippp device ioctl */intisdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg){	unsigned long val;	int r,i,j;	struct ippp_struct *is;	isdn_net_local *lp;	struct isdn_ppp_comp_data data;	void __user *argp = (void __user *)arg;	is = (struct ippp_struct *) file->private_data;	lp = is->lp;	if (is->debug & 0x1)		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);	if (!(is->state & IPPP_OPEN))		return -EINVAL;	switch (cmd) {		case PPPIOCBUNDLE:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -