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

📄 af_wanpipe.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
		sk_free(sk);		return NULL;	}	memset(wan_opt, 0x00, sizeof(struct wanpipe_opt));	sk->protinfo.af_wanpipe = wan_opt;	sk->protinfo.destruct_hook = wan_opt;	/* Use timer to send data to the driver. This will act         * as a BH handler for sendmsg functions */	sk->protinfo.af_wanpipe->tx_timer.data=(unsigned long)sk;	sk->protinfo.af_wanpipe->tx_timer.function=wanpipe_delayed_transmit;	MOD_INC_USE_COUNT;	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->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->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->write_queue. *===========================================================*/static int wanpipe_sendmsg(struct socket *sock, struct msghdr *msg, int len,			  struct scm_cookie *scm){	struct sock *sk = sock->sk;	struct wan_sockaddr_ll *saddr=(struct wan_sockaddr_ll *)msg->msg_name;	struct sk_buff *skb;	netdevice_t *dev;	unsigned short proto;	unsigned char *addr;	int ifindex, err, reserve = 0;		if (!sk->zapped)		return -ENETDOWN;	if (sk->state != WANSOCK_CONNECTED)		return -ENOTCONN;		if (msg->msg_flags&~MSG_DONTWAIT) 		return(-EINVAL);	/* it was <=, now one can send         * zero length packets */	if (len < sizeof(x25api_hdr_t))		return -EINVAL;	if (saddr == NULL) {		ifindex	= sk->bound_dev_if;		proto	= sk->num;		addr	= NULL;	}else{		if (msg->msg_namelen < sizeof(struct wan_sockaddr_ll)){ 			return -EINVAL;		}		ifindex = 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;	}      #ifndef LINUX_2_4	dev_lock_list();      #endif            #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)	skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 				msg->msg_flags & MSG_DONTWAIT, &err);      #else	skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, 				msg->msg_flags & MSG_DONTWAIT, &err);      #endif	if (skb==NULL){		goto out_unlock;	}			skb_reserve(skb, (dev->hard_header_len+15)&~15);	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->priority;	skb->pkt_type = WAN_PACKET_DATA;	err = -ENETDOWN;	if (!(dev->flags & IFF_UP))		goto out_free;      #ifndef LINUX_2_4	dev_unlock_list();      #endif		if (atomic_read(&sk->wmem_alloc) + skb->truesize > (unsigned int)sk->sndbuf){		kfree_skb(skb);		return -ENOBUFS;	}	skb_queue_tail(&sk->write_queue,skb);	atomic_inc(&sk->protinfo.af_wanpipe->packet_sent);	if (!(test_and_set_bit(0,&sk->protinfo.af_wanpipe->timer))){		del_timer(&sk->protinfo.af_wanpipe->tx_timer);		sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+1;		add_timer(&sk->protinfo.af_wanpipe->tx_timer);	}			return(len);out_free:	kfree_skb(skb);out_unlock:#ifndef LINUX_2_4	dev_unlock_list();#endif	return err;}/*============================================================ * wanpipe_delayed_tarnsmit * *	Transmit bottom half handeler. It dequeues packets *      from 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;	netdevice_t *dev = sk->protinfo.af_wanpipe->dev;	sdla_t *card = (sdla_t*)sk->protinfo.af_wanpipe->card;	if (!card || !dev){		clear_bit (0,&sk->protinfo.af_wanpipe->timer);		DBG_PRINTK(KERN_INFO "wansock: Transmit delay, no dev or card\n");		return;	}		if (sk->state != WANSOCK_CONNECTED || !sk->zapped){			clear_bit (0,&sk->protinfo.af_wanpipe->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)){		sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+SLOW_BACKOFF;		add_timer(&sk->protinfo.af_wanpipe->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);		sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+SLOW_BACKOFF;		add_timer(&sk->protinfo.af_wanpipe->tx_timer);		return;	}			/* Check for a packet in the fifo and send */	if ((skb=skb_dequeue(&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->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(&sk->protinfo.af_wanpipe->packet_sent);			if (skb_peek(&sk->write_queue) == NULL){				/* If there is nothing to send, kick				 * the poll routine, which will trigger				 * the application to send more data */				sk->data_ready(sk,0);				clear_bit (0,&sk->protinfo.af_wanpipe->timer);			}else{				/* Reschedule as fast as possible */				sk->protinfo.af_wanpipe->tx_timer.expires=jiffies+1;				add_timer(&sk->protinfo.af_wanpipe->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 exection.  The acutal command *      structure is placed into a sock mbox structure  *      (sk->protinfo.af_wanpipe->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){	netdevice_t *dev;	wanpipe_common_t *chan=NULL;	int err=0;	DECLARE_WAITQUEUE(wait, current);		dev = dev_get_by_index(sk->bound_dev_if);	if (dev == NULL){		printk(KERN_INFO "wansock: Exec failed no dev %i\n",			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 (!sk->protinfo.af_wanpipe->mbox){		printk(KERN_INFO "wansock: In execute without MBOX\n");		return -EINVAL;	}	((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.command=cmd;		((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.lcn = 					sk->protinfo.af_wanpipe->lcn;	((mbox_cmd_t*)sk->protinfo.af_wanpipe->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->sleep,&wait);	current->state = TASK_INTERRUPTIBLE;	for (;;){		if (((mbox_cmd_t*)sk->protinfo.af_wanpipe->mbox)->cmd.result != 0x7F) {			err = 0;			break;		}		if (signal_pending(current)) {			err = -ERESTARTSYS;			break;		}		schedule();	}	current->state = TASK_RUNNING;	remove_wait_queue(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;	if ((!atomic_read(&sk->wmem_alloc) && !atomic_read(&sk->rmem_alloc)) ||	    (++sk->protinfo.af_wanpipe->force == 5)) {		if (atomic_read(&sk->wmem_alloc) || atomic_read(&sk->rmem_alloc))			printk(KERN_INFO "wansock: Warning, Packet Discarded due to sock shutdown!\n");		if (sk->protinfo.af_wanpipe){			kfree(sk->protinfo.af_wanpipe);			sk->protinfo.af_wanpipe=NULL;		}		              #ifdef LINUX_2_4		if (atomic_read(&sk->refcnt) != 1){			atomic_set(&sk->refcnt,1);			DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :delay.\n",					atomic_read(&sk->refcnt));		}		sock_put(sk);              #else		sk_free(sk);              #endif		atomic_dec(&wanpipe_socks_nr);		MOD_DEC_USE_COUNT;		return;	}	sk->timer.expires=jiffies+5*HZ;	add_timer(&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){	netdevice_t *dev;	wanpipe_common_t *chan=NULL;	sk->zapped=0;	sk->state = WANSOCK_DISCONNECTED;	sk->protinfo.af_wanpipe->dev = NULL;	dev = dev_get_by_index(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 (netdevice_t *dev, struct sock *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=sk->protinfo.af_wanpipe->mbox;	chan->tx_timer = &sk->protinfo.af_wanpipe->tx_timer;	sk->protinfo.af_wanpipe->dev=dev;	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 (netdevice_t *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. *===========================================================*/#ifdef LINUX_2_4static int wanpipe_release(struct socket *sock)#elsestatic int wanpipe_release(struct socket *sock, struct socket *peersock)#endif{	#ifndef LINUX_2_4	struct sk_buff	*skb;#endif	struct sock *sk = sock->sk;	struct sock **skp;		if (!sk)		return 0;	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(&sk->protinfo.af_wanpipe->tx_timer);	/*	 *	Unhook packet receive handler.	 */	if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED && sk->zapped){		netdevice_t *dev = dev_get_by_index(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->state);			dev_put(dev);		}		}

⌨️ 快捷键说明

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