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

📄 af_wanpipe.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	wp_sk(sk) = wan_opt;	/* Use timer to send data to the driver. This will act         * as a BH handler for sendmsg functions */	init_timer(&wan_opt->tx_timer);	wan_opt->tx_timer.data	   = (unsigned long)sk;	wan_opt->tx_timer.function = wanpipe_delayed_transmit;	sock_init_data(NULL, sk);	return sk;}/*============================================================ * wanpipe_sendmsg * *	This function implements a sendto() system call, *      for AF_WANPIPE socket family.  *      During socket bind() sk->sk_bound_dev_if is initialized *      to a correct network device. This number is used *      to find a network device to which the packet should *      be passed to. * *      Each packet is queued into sk->sk_write_queue and  *      delayed transmit bottom half handler is marked for  *      execution. * *      A socket must be in WANSOCK_CONNECTED state before *      a packet is queued into sk->sk_write_queue. *===========================================================*/static int wanpipe_sendmsg(struct kiocb *iocb, struct socket *sock,			   struct msghdr *msg, int len){	wanpipe_opt *wp;	struct sock *sk = sock->sk;	struct wan_sockaddr_ll *saddr=(struct wan_sockaddr_ll *)msg->msg_name;	struct sk_buff *skb;	struct net_device *dev;	unsigned short proto;	unsigned char *addr;	int ifindex, err, reserve = 0;		if (!sk->sk_zapped)		return -ENETDOWN;	if (sk->sk_state != WANSOCK_CONNECTED)		return -ENOTCONN;		if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) 		return(-EINVAL);	/* it was <=, now one can send         * zero length packets */	if (len < sizeof(x25api_hdr_t))		return -EINVAL;	wp = wp_sk(sk);	if (saddr == NULL) {		ifindex	= sk->sk_bound_dev_if;		proto	= wp->num;		addr	= NULL;	}else{		if (msg->msg_namelen < sizeof(struct wan_sockaddr_ll)){ 			return -EINVAL;		}		ifindex = sk->sk_bound_dev_if;		proto	= saddr->sll_protocol;		addr	= saddr->sll_addr;	}	dev = dev_get_by_index(ifindex);	if (dev == NULL){		printk(KERN_INFO "wansock: Send failed, dev index: %i\n",ifindex);		return -ENXIO;	}	dev_put(dev);		if (sock->type == SOCK_RAW)		reserve = dev->hard_header_len;	if (len > dev->mtu+reserve){  		return -EMSGSIZE;	}	skb = sock_alloc_send_skb(sk, len + LL_RESERVED_SPACE(dev),				msg->msg_flags & MSG_DONTWAIT, &err);	if (skb==NULL){		goto out_unlock;	}			skb_reserve(skb, LL_RESERVED_SPACE(dev));	skb->nh.raw = skb->data;	/* Returns -EFAULT on error */	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);	if (err){		goto out_free;	}	if (dev->hard_header) {		int res;		err = -EINVAL;		res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len);		if (res<0){			goto out_free;		}	}	skb->protocol = proto;	skb->dev = dev;	skb->priority = sk->sk_priority;	skb->pkt_type = WAN_PACKET_DATA;	err = -ENETDOWN;	if (!(dev->flags & IFF_UP))		goto out_free;	if (atomic_read(&sk->sk_wmem_alloc) + skb->truesize >	    (unsigned int)sk->sk_sndbuf){		kfree_skb(skb);		return -ENOBUFS;	}	skb_queue_tail(&sk->sk_write_queue,skb);	atomic_inc(&wp->packet_sent);	if (!(test_and_set_bit(0, &wp->timer)))		mod_timer(&wp->tx_timer, jiffies + 1);		return(len);out_free:	kfree_skb(skb);out_unlock:	return err;}/*============================================================ * wanpipe_delayed_tarnsmit * *	Transmit bottom half handler. It dequeues packets *      from sk->sk_write_queue and passes them to the  *      driver.  If the driver is busy, the packet is  *      re-enqueued.   * *      Packet Sent counter is decremented on successful *      transmission.  *===========================================================*/static void wanpipe_delayed_transmit (unsigned long data){	struct sock *sk=(struct sock *)data;	struct sk_buff *skb;	wanpipe_opt *wp = wp_sk(sk);	struct net_device *dev = wp->dev;	sdla_t *card = (sdla_t*)wp->card;	if (!card || !dev){		clear_bit(0, &wp->timer);		DBG_PRINTK(KERN_INFO "wansock: Transmit delay, no dev or card\n");		return;	}		if (sk->sk_state != WANSOCK_CONNECTED || !sk->sk_zapped) {		clear_bit(0, &wp->timer);		DBG_PRINTK(KERN_INFO "wansock: Tx Timer, State not CONNECTED\n");		return;	}		/* If driver is executing command, we must offload         * the board by not sending data. Otherwise a          * pending command will never get a free buffer         * to execute */ 		if (atomic_read(&card->u.x.command_busy)){		wp->tx_timer.expires = jiffies + SLOW_BACKOFF;		add_timer(&wp->tx_timer);		DBG_PRINTK(KERN_INFO "wansock: Tx Timer, command bys BACKOFF\n");		return;	}		if (test_and_set_bit(0,&wanpipe_tx_critical)){		printk(KERN_INFO "WanSock: Tx timer critical %s\n",dev->name);		wp->tx_timer.expires = jiffies + SLOW_BACKOFF;		add_timer(&wp->tx_timer);		return;	}			/* Check for a packet in the fifo and send */	if ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL){		if (dev->hard_start_xmit(skb, dev) != 0){						/* Driver failed to transmit, re-enqueue                         * the packet and retry again later */			skb_queue_head(&sk->sk_write_queue,skb);			clear_bit(0,&wanpipe_tx_critical);			return;		}else{			/* Packet Sent successful. Check for more packets                         * if more packets, re-trigger the transmit routine                          * other wise exit                         */			atomic_dec(&wp->packet_sent);			if (skb_peek(&sk->sk_write_queue) == NULL) {				/* If there is nothing to send, kick				 * the poll routine, which will trigger				 * the application to send more data */				sk->sk_data_ready(sk, 0);				clear_bit(0, &wp->timer);			}else{				/* Reschedule as fast as possible */				wp->tx_timer.expires = jiffies + 1;				add_timer(&wp->tx_timer);			}		}	}	clear_bit(0,&wanpipe_tx_critical);}/*============================================================ * execute_command  * *	Execute x25api commands.  The atomic variable *      chan->command is used to indicate to the driver that *      command is pending for execution.  The acutal command *      structure is placed into a sock mbox structure  *      (wp_sk(sk)->mbox). * *      The sock private structure, mbox is *      used as shared memory between sock and the driver. *      Driver uses the sock mbox to execute the command *      and return the result.   * *      For all command except PLACE CALL, the function *      waits for the result.  PLACE CALL can be ether *      blocking or nonblocking. The user sets this option *      via ioctl call. *===========================================================*/static int execute_command(struct sock *sk,  unsigned char cmd, unsigned int flags){	wanpipe_opt *wp = wp_sk(sk);	struct net_device *dev;	wanpipe_common_t *chan=NULL;	int err=0;	DECLARE_WAITQUEUE(wait, current);		dev = dev_get_by_index(sk->sk_bound_dev_if);	if (dev == NULL){		printk(KERN_INFO "wansock: Exec failed no dev %i\n",			sk->sk_bound_dev_if);		return -ENODEV;	}	dev_put(dev);	if ((chan=dev->priv) == NULL){		printk(KERN_INFO "wansock: Exec cmd failed no priv area\n");		return -ENODEV;	}	if (atomic_read(&chan->command)){		printk(KERN_INFO "wansock: ERROR: Command already running %x, %s\n",			atomic_read(&chan->command),dev->name);		return -EINVAL;	}	if (!wp->mbox) {		printk(KERN_INFO "wansock: In execute without MBOX\n");		return -EINVAL;	}	((mbox_cmd_t*)wp->mbox)->cmd.command = cmd;		((mbox_cmd_t*)wp->mbox)->cmd.lcn     = wp->lcn;	((mbox_cmd_t*)wp->mbox)->cmd.result  = 0x7F;	if (flags & O_NONBLOCK){		cmd |= 0x80;		atomic_set(&chan->command, cmd);	}else{		atomic_set(&chan->command, cmd);	}	add_wait_queue(sk->sk_sleep,&wait);	current->state = TASK_INTERRUPTIBLE;	for (;;){		if (((mbox_cmd_t*)wp->mbox)->cmd.result != 0x7F) {			err = 0;			break;		}		if (signal_pending(current)) {			err = -ERESTARTSYS;			break;		}		schedule();	}	current->state = TASK_RUNNING;	remove_wait_queue(sk->sk_sleep,&wait);		return err;}/*============================================================ * wanpipe_destroy_timer  * *	Used by wanpipe_release, to delay release of *      the socket. *===========================================================*/static void wanpipe_destroy_timer(unsigned long data){	struct sock *sk=(struct sock *)data;	wanpipe_opt *wp = wp_sk(sk);	if ((!atomic_read(&sk->sk_wmem_alloc) &&	     !atomic_read(&sk->sk_rmem_alloc)) ||	    (++wp->force == 5)) {		if (atomic_read(&sk->sk_wmem_alloc) ||		    atomic_read(&sk->sk_rmem_alloc))			printk(KERN_INFO "wansock: Warning, Packet Discarded due to sock shutdown!\n");		kfree(wp);		wp_sk(sk) = NULL;				if (atomic_read(&sk->sk_refcnt) != 1) {			atomic_set(&sk->sk_refcnt, 1);			DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :delay.\n",					atomic_read(&sk->sk_refcnt));		}		sock_put(sk);		atomic_dec(&wanpipe_socks_nr);		return;	}	sk->sk_timer.expires = jiffies + 5 * HZ;	add_timer(&sk->sk_timer);	printk(KERN_INFO "wansock: packet sk destroy delayed\n");}/*============================================================ * wanpipe_unlink_driver * * 	When the socket is released, this function is  *      used to remove links that bind the sock and the *      driver together.   *===========================================================*/static void wanpipe_unlink_driver (struct sock *sk){	struct net_device *dev;	wanpipe_common_t *chan=NULL;	sk->sk_zapped = 0;	sk->sk_state = WANSOCK_DISCONNECTED;	wp_sk(sk)->dev = NULL;	dev = dev_get_by_index(sk->sk_bound_dev_if);	if (!dev){		printk(KERN_INFO "wansock: No dev on release\n");		return;	}				dev_put(dev);	if ((chan = dev->priv) == NULL){		printk(KERN_INFO "wansock: No Priv Area on release\n");		return;	}	set_bit(0,&chan->common_critical);	chan->sk=NULL;	chan->func=NULL;	chan->mbox=NULL;	chan->tx_timer=NULL;	clear_bit(0,&chan->common_critical);	release_device(dev);		return;}/*============================================================ * wanpipe_link_driver * * 	Upon successful bind(), sock is linked to a driver *      by binding in the wanpipe_rcv() bottom half handler *      to the driver function pointer, as well as sock and *      sock mailbox addresses.  This way driver can pass *      data up the socket. *===========================================================*/static void wanpipe_link_driver(struct net_device *dev, struct sock *sk){	wanpipe_opt *wp = wp_sk(sk);	wanpipe_common_t *chan = dev->priv;	if (!chan)		return;	set_bit(0,&chan->common_critical);	chan->sk=sk;	chan->func=wanpipe_rcv;	chan->mbox = wp->mbox;	chan->tx_timer = &wp->tx_timer;	wp->dev = dev;	sk->sk_zapped = 1;	clear_bit(0,&chan->common_critical);}/*============================================================ * release_device * *   	During sock release, clear a critical bit, which  *      marks the device a being taken. *===========================================================*/static void release_device(struct net_device *dev){	wanpipe_common_t *chan=dev->priv;	clear_bit(0,(void*)&chan->rw_bind);}/*============================================================ * wanpipe_release * *	Close a PACKET socket. This is fairly simple. We  *      immediately go to 'closed' state and remove our  *      protocol entry in the device list. *===========================================================*/static int wanpipe_release(struct socket *sock){	wanpipe_opt *wp;	struct sock *sk = sock->sk;		if (!sk)		return 0;	wp = wp_sk(sk);	check_write_queue(sk);	/* Kill the tx timer, if we don't kill it now, the timer         * will run after we kill the sock.  Timer code will          * try to access the sock which has been killed and cause         * kernel panic */	del_timer(&wp->tx_timer);	/*	 *	Unhook packet receive handler.	 */	if (wp->num == htons(X25_PROT) &&	    sk->sk_state != WANSOCK_DISCONNECTED && sk->sk_zapped) {		struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if);		wanpipe_common_t *chan;		if (dev){			chan=dev->priv;			atomic_set(&chan->disconnect,1);			DBG_PRINTK(KERN_INFO "wansock: Sending Clear Indication %i\n",					sk->sk_state);			dev_put(dev);		}		}	set_bit(1,&wanpipe_tx_critical);	write_lock(&wanpipe_sklist_lock);	sk_del_node_init(sk);	write_unlock(&wanpipe_sklist_lock);	clear_bit(1,&wanpipe_tx_critical);		release_driver(sk);		/*	 *	Now the socket is dead. No more input will appear.	 */	sk->sk_state_change(sk);	/* It is useless. Just for sanity. */	sock->sk = NULL;	sk->sk_socket = NULL;	sock_set_flag(sk, SOCK_DEAD);	/* Purge queues */	skb_queue_purge(&sk->sk_receive_queue);	skb_queue_purge(&sk->sk_write_queue);	skb_queue_purge(&sk->sk_error_queue);	if (atomic_read(&sk->sk_rmem_alloc) ||	    atomic_read(&sk->sk_wmem_alloc)) {		del_timer(&sk->sk_timer);		printk(KERN_INFO "wansock: Killing in Timer R %i , W %i\n",

⌨️ 快捷键说明

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