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

📄 isdn_ppp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
#ifdef CONFIG_ISDN_MPP			if (!(is->state & IPPP_CONNECT))				return -EINVAL;			if ((r = get_arg(argp, &val, sizeof(val) )))				return r;			printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",			       (int) min, (int) is->unit, (int) val);			return isdn_ppp_bundle(is, val);#else			return -1;#endif			break;		case PPPIOCGUNIT:	/* get ppp/isdn unit number */			if ((r = set_arg(argp, &is->unit, sizeof(is->unit) )))				return r;			break;		case PPPIOCGIFNAME:			if(!lp)				return -EINVAL;			if ((r = set_arg(argp, lp->name, strlen(lp->name))))				return r;			break;		case PPPIOCGMPFLAGS:	/* get configuration flags */			if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg) )))				return r;			break;		case PPPIOCSMPFLAGS:	/* set configuration flags */			if ((r = get_arg(argp, &val, sizeof(val) )))				return r;			is->mpppcfg = val;			break;		case PPPIOCGFLAGS:	/* get configuration flags */			if ((r = set_arg(argp, &is->pppcfg,sizeof(is->pppcfg) )))				return r;			break;		case PPPIOCSFLAGS:	/* set configuration flags */			if ((r = get_arg(argp, &val, sizeof(val) ))) {				return r;			}			if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {				if (lp) {					/* OK .. we are ready to send buffers */					is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */					netif_wake_queue(&lp->netdev->dev);					break;				}			}			is->pppcfg = val;			break;		case PPPIOCGIDLE:	/* get idle time information */			if (lp) {				struct ppp_idle pidle;				pidle.xmit_idle = pidle.recv_idle = lp->huptimer;				if ((r = set_arg(argp, &pidle,sizeof(struct ppp_idle))))					 return r;			}			break;		case PPPIOCSMRU:	/* set receive unit size for PPP */			if ((r = get_arg(argp, &val, sizeof(val) )))				return r;			is->mru = val;			break;		case PPPIOCSMPMRU:			break;		case PPPIOCSMPMTU:			break;		case PPPIOCSMAXCID:	/* set the maximum compression slot id */			if ((r = get_arg(argp, &val, sizeof(val) )))				return r;			val++;			if (is->maxcid != val) {#ifdef CONFIG_ISDN_PPP_VJ				struct slcompress *sltmp;#endif				if (is->debug & 0x1)					printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);				is->maxcid = val;#ifdef CONFIG_ISDN_PPP_VJ				sltmp = slhc_init(16, val);				if (!sltmp) {					printk(KERN_ERR "ippp, can't realloc slhc struct\n");					return -ENOMEM;				}				if (is->slcomp)					slhc_free(is->slcomp);				is->slcomp = sltmp;#endif			}			break;		case PPPIOCGDEBUG:			if ((r = set_arg(argp, &is->debug, sizeof(is->debug) )))				return r;			break;		case PPPIOCSDEBUG:			if ((r = get_arg(argp, &val, sizeof(val) )))				return r;			is->debug = val;			break;		case PPPIOCGCOMPRESSORS:			{				unsigned long protos[8] = {0,};				struct isdn_ppp_compressor *ipc = ipc_head;				while(ipc) {					j = ipc->num / (sizeof(long)*8);					i = ipc->num % (sizeof(long)*8);					if(j < 8)						protos[j] |= (0x1<<i);					ipc = ipc->next;				}				if ((r = set_arg(argp,protos,8*sizeof(long) )))					return r;			}			break;		case PPPIOCSCOMPRESSOR:			if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))				return r;			return isdn_ppp_set_compressor(is, &data);		case PPPIOCGCALLINFO:			{				struct pppcallinfo pci;				memset((char *) &pci,0,sizeof(struct pppcallinfo));				if(lp)				{					strncpy(pci.local_num,lp->msn,63);					if(lp->dial) {						strncpy(pci.remote_num,lp->dial->num,63);					}					pci.charge_units = lp->charge;					if(lp->outgoing)						pci.calltype = CALLTYPE_OUTGOING;					else						pci.calltype = CALLTYPE_INCOMING;					if(lp->flags & ISDN_NET_CALLBACK)						pci.calltype |= CALLTYPE_CALLBACK;				}				return set_arg(argp,&pci,sizeof(struct pppcallinfo));			}#ifdef CONFIG_IPPP_FILTER		case PPPIOCSPASS:			{				struct sock_filter *code;				int len = get_filter(argp, &code);				if (len < 0)					return len;				kfree(is->pass_filter);				is->pass_filter = code;				is->pass_len = len;				break;			}		case PPPIOCSACTIVE:			{				struct sock_filter *code;				int len = get_filter(argp, &code);				if (len < 0)					return len;				kfree(is->active_filter);				is->active_filter = code;				is->active_len = len;				break;			}#endif /* CONFIG_IPPP_FILTER */		default:			break;	}	return 0;}unsigned intisdn_ppp_poll(struct file *file, poll_table * wait){	u_int mask;	struct ippp_buf_queue *bf, *bl;	u_long flags;	struct ippp_struct *is;	is = file->private_data;	if (is->debug & 0x2)		printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",				MINOR(file->f_dentry->d_inode->i_rdev));	/* just registers wait_queue hook. This doesn't really wait. */	poll_wait(file, &is->wq, wait);	if (!(is->state & IPPP_OPEN)) {		if(is->state == IPPP_CLOSEWAIT)			return POLLHUP;		printk(KERN_DEBUG "isdn_ppp: device not open\n");		return POLLERR;	}	/* we're always ready to send .. */	mask = POLLOUT | POLLWRNORM;	spin_lock_irqsave(&is->buflock, flags);	bl = is->last;	bf = is->first;	/*	 * if IPPP_NOBLOCK is set we return even if we have nothing to read	 */	if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {		is->state &= ~IPPP_NOBLOCK;		mask |= POLLIN | POLLRDNORM;	}	spin_unlock_irqrestore(&is->buflock, flags);	return mask;}/* *  fill up isdn_ppp_read() queue .. */static intisdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot){	struct ippp_buf_queue *bf, *bl;	u_long flags;	u_char *nbuf;	struct ippp_struct *is;	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {		printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);		return 0;	}	is = ippp_table[slot];	if (!(is->state & IPPP_CONNECT)) {		printk(KERN_DEBUG "ippp: device not activated.\n");		return 0;	}	nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);	if (!nbuf) {		printk(KERN_WARNING "ippp: Can't alloc buf\n");		return 0;	}	nbuf[0] = PPP_ALLSTATIONS;	nbuf[1] = PPP_UI;	nbuf[2] = proto >> 8;	nbuf[3] = proto & 0xff;	memcpy(nbuf + 4, buf, len);	spin_lock_irqsave(&is->buflock, flags);	bf = is->first;	bl = is->last;	if (bf == bl) {		printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");		bf = bf->next;		kfree(bf->buf);		is->first = bf;	}	bl->buf = (char *) nbuf;	bl->len = len + 4;	is->last = bl->next;	spin_unlock_irqrestore(&is->buflock, flags);	wake_up_interruptible(&is->wq);	return len;}/* * read() .. non-blocking: ipppd calls it only after select() *           reports, that there is data */intisdn_ppp_read(int min, struct file *file, char __user *buf, int count){	struct ippp_struct *is;	struct ippp_buf_queue *b;	u_long flags;	u_char *save_buf;	is = file->private_data;	if (!(is->state & IPPP_OPEN))		return 0;	if (!access_ok(VERIFY_WRITE, buf, count))		return -EFAULT;	spin_lock_irqsave(&is->buflock, flags);	b = is->first->next;	save_buf = b->buf;	if (!save_buf) {		spin_unlock_irqrestore(&is->buflock, flags);		return -EAGAIN;	}	if (b->len < count)		count = b->len;	b->buf = NULL;	is->first = b;	spin_unlock_irqrestore(&is->buflock, flags);	copy_to_user(buf, save_buf, count);	kfree(save_buf);	return count;}/* * ipppd wanna write a packet to the card .. non-blocking */intisdn_ppp_write(int min, struct file *file, const char __user *buf, int count){	isdn_net_local *lp;	struct ippp_struct *is;	int proto;	unsigned char protobuf[4];	is = file->private_data;	if (!(is->state & IPPP_CONNECT))		return 0;	lp = is->lp;	/* -> push it directly to the lowlevel interface */	if (!lp)		printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");	else {		/*		 * Don't reset huptimer for		 * LCP packets. (Echo requests).		 */		if (copy_from_user(protobuf, buf, 4))			return -EFAULT;		proto = PPP_PROTOCOL(protobuf);		if (proto != PPP_LCP)			lp->huptimer = 0;		if (lp->isdn_device < 0 || lp->isdn_channel < 0)			return 0;		if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&			lp->dialstate == 0 &&		    (lp->flags & ISDN_NET_CONNECTED)) {			unsigned short hl;			struct sk_buff *skb;			/*			 * we need to reserve enought space in front of			 * sk_buff. old call to dev_alloc_skb only reserved			 * 16 bytes, now we are looking what the driver want			 */			hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;			skb = alloc_skb(hl+count, GFP_ATOMIC);			if (!skb) {				printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");				return count;			}			skb_reserve(skb, hl);			if (copy_from_user(skb_put(skb, count), buf, count))			{				kfree_skb(skb);				return -EFAULT;			}			if (is->debug & 0x40) {				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);				isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot);			}			isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */			isdn_net_write_super(lp, skb);		}	}	return count;}/* * init memory, structures etc. */intisdn_ppp_init(void){	int i,	 j;	 #ifdef CONFIG_ISDN_MPP	if( isdn_ppp_mp_bundle_array_init() < 0 )		return -ENOMEM;#endif /* CONFIG_ISDN_MPP */	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {		if (!(ippp_table[i] = (struct ippp_struct *)		      kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {			printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");			for (j = 0; j < i; j++)				kfree(ippp_table[j]);			return -1;		}		memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));		spin_lock_init(&ippp_table[i]->buflock);		ippp_table[i]->state = 0;		ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;		ippp_table[i]->last = ippp_table[i]->rq;		for (j = 0; j < NUM_RCV_BUFFS; j++) {			ippp_table[i]->rq[j].buf = NULL;			ippp_table[i]->rq[j].last = ippp_table[i]->rq +			    (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;			ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;		}	}	return 0;}voidisdn_ppp_cleanup(void){	int i;	for (i = 0; i < ISDN_MAX_CHANNELS; i++)		kfree(ippp_table[i]);#ifdef CONFIG_ISDN_MPP	kfree(isdn_ppp_bundle_arr);#endif /* CONFIG_ISDN_MPP */}/* * check for address/control field and skip if allowed * retval != 0 -> discard packet silently */static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) {	if (skb->len < 1)		return -1;	if (skb->data[0] == 0xff) {		if (skb->len < 2)			return -1;		if (skb->data[1] != 0x03)			return -1;		// skip address/control (AC) field		skb_pull(skb, 2);	} else { 		if (is->pppcfg & SC_REJ_COMP_AC)			// if AC compression was not negotiated, but used, discard packet			return -1;	}	return 0;}/* * get the PPP protocol header and pull skb * retval < 0 -> discard packet silently */static int isdn_ppp_strip_proto(struct sk_buff *skb) {	int proto;		if (skb->len < 1)		return -1;	if (skb->data[0] & 0x1) {		// protocol field is compressed		proto = skb->data[0];		skb_pull(skb, 1);	} else {		if (skb->len < 2)			return -1;		proto = ((int) skb->data[0] << 8) + skb->data[1];		skb_pull(skb, 2);	}	return proto;}/* * handler for incoming packets on a syncPPP interface */void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb){	struct ippp_struct *is;	int slot;	int proto;	if (net_dev->local->master)		BUG(); // we're called with the master device always	slot = lp->ppp_slot;	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",			lp->ppp_slot);

⌨️ 快捷键说明

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