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

📄 af_econet.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void *arg){	struct ifreq ifr;	struct ec_device *edev;	struct net_device *dev;	struct sockaddr_ec *sec;	/*	 *	Fetch the caller's info block into kernel space	 */	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))		return -EFAULT;	if ((dev = dev_get_by_name(ifr.ifr_name)) == NULL) 		return -ENODEV;	sec = (struct sockaddr_ec *)&ifr.ifr_addr;	switch (cmd)	{	case SIOCSIFADDR:		edev = dev->ec_ptr;		if (edev == NULL)		{			/* Magic up a new one. */			edev = kmalloc(sizeof(struct ec_device), GFP_KERNEL);			if (edev == NULL) {				printk("af_ec: memory squeeze.\n");				dev_put(dev);				return -ENOMEM;			}			memset(edev, 0, sizeof(struct ec_device));			dev->ec_ptr = edev;		}		else			net2dev_map[edev->net] = NULL;		edev->station = sec->addr.station;		edev->net = sec->addr.net;		net2dev_map[sec->addr.net] = dev;		if (!net2dev_map[0])			net2dev_map[0] = dev;		dev_put(dev);		return 0;	case SIOCGIFADDR:		edev = dev->ec_ptr;		if (edev == NULL)		{			dev_put(dev);			return -ENODEV;		}		memset(sec, 0, sizeof(struct sockaddr_ec));		sec->addr.station = edev->station;		sec->addr.net = edev->net;		sec->sec_family = AF_ECONET;		dev_put(dev);		if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))			return -EFAULT;		return 0;	}	dev_put(dev);	return -EINVAL;}/* *	Handle generic ioctls */static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	int pid;	switch(cmd) 	{		case FIOSETOWN:		case SIOCSPGRP:			if (get_user(pid, (int *) arg))				return -EFAULT; 			if (current->pid != pid && current->pgrp != -pid && !capable(CAP_NET_ADMIN))				return -EPERM;			sk->proc = pid;			return(0);		case FIOGETOWN:		case SIOCGPGRP:			return put_user(sk->proc, (int *)arg);		case SIOCGSTAMP:			if(sk->stamp.tv_sec==0)				return -ENOENT;			return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;		case SIOCGIFFLAGS:		case SIOCSIFFLAGS:		case SIOCGIFCONF:		case SIOCGIFMETRIC:		case SIOCSIFMETRIC:		case SIOCGIFMEM:		case SIOCSIFMEM:		case SIOCGIFMTU:		case SIOCSIFMTU:		case SIOCSIFLINK:		case SIOCGIFHWADDR:		case SIOCSIFHWADDR:		case SIOCSIFMAP:		case SIOCGIFMAP:		case SIOCSIFSLAVE:		case SIOCGIFSLAVE:		case SIOCGIFINDEX:		case SIOCGIFNAME:		case SIOCGIFCOUNT:		case SIOCSIFHWBROADCAST:			return(dev_ioctl(cmd,(void *) arg));		case SIOCSIFADDR:		case SIOCGIFADDR:			return ec_dev_ioctl(sock, cmd, (void *)arg);			break;		default:			return(dev_ioctl(cmd,(void *) arg));	}	/*NOTREACHED*/	return 0;}static struct net_proto_family econet_family_ops = {	family:		PF_ECONET,	create:		econet_create,};static struct proto_ops SOCKOPS_WRAPPED(econet_ops) = {	family:		PF_ECONET,	release:	econet_release,	bind:		econet_bind,	connect:	sock_no_connect,	socketpair:	sock_no_socketpair,	accept:		sock_no_accept,	getname:	econet_getname, 	poll:		datagram_poll,	ioctl:		econet_ioctl,	listen:		sock_no_listen,	shutdown:	sock_no_shutdown,	setsockopt:	sock_no_setsockopt,	getsockopt:	sock_no_getsockopt,	sendmsg:	econet_sendmsg,	recvmsg:	econet_recvmsg,	mmap:		sock_no_mmap,	sendpage:	sock_no_sendpage,};#include <linux/smp_lock.h>SOCKOPS_WRAP(econet, PF_ECONET);/* *	Find the listening socket, if any, for the given data. */static struct sock *ec_listening_socket(unsigned char port, unsigned char				 station, unsigned char net){	struct sock *sk = econet_sklist;	while (sk)	{		struct econet_opt *opt = sk->protinfo.af_econet;		if ((opt->port == port || opt->port == 0) && 		    (opt->station == station || opt->station == 0) &&		    (opt->net == net || opt->net == 0))			return sk;		sk = sk->next;	}	return NULL;}/* *	Queue a received packet for a socket. */static int ec_queue_packet(struct sock *sk, struct sk_buff *skb,			   unsigned char stn, unsigned char net,			   unsigned char cb, unsigned char port){	struct ec_cb *eb = (struct ec_cb *)&skb->cb;	struct sockaddr_ec *sec = (struct sockaddr_ec *)&eb->sec;	memset(sec, 0, sizeof(struct sockaddr_ec));	sec->sec_family = AF_ECONET;	sec->type = ECTYPE_PACKET_RECEIVED;	sec->port = port;	sec->cb = cb;	sec->addr.net = net;	sec->addr.station = stn;	return sock_queue_rcv_skb(sk, skb);}#ifdef CONFIG_ECONET_AUNUDP/* *	Send an AUN protocol response.  */static void aun_send_response(__u32 addr, unsigned long seq, int code, int cb){	struct sockaddr_in sin;	struct iovec iov;	struct aunhdr ah;	struct msghdr udpmsg;	int err;	mm_segment_t oldfs;		memset(&sin, 0, sizeof(sin));	sin.sin_family = AF_INET;	sin.sin_port = htons(AUN_PORT);	sin.sin_addr.s_addr = addr;	ah.code = code;	ah.pad = 0;	ah.port = 0;	ah.cb = cb;	ah.handle = seq;	iov.iov_base = (void *)&ah;	iov.iov_len = sizeof(ah);	udpmsg.msg_name = (void *)&sin;	udpmsg.msg_namelen = sizeof(sin);	udpmsg.msg_iov = &iov;	udpmsg.msg_iovlen = 1;	udpmsg.msg_control = NULL;	udpmsg.msg_controllen = 0;	udpmsg.msg_flags=0;	oldfs = get_fs(); set_fs(KERNEL_DS);	err = sock_sendmsg(udpsock, &udpmsg, sizeof(ah));	set_fs(oldfs);}/* *	Handle incoming AUN packets.  Work out if anybody wants them, *	and send positive or negative acknowledgements as appropriate. */static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len){	struct iphdr *ip = skb->nh.iph;	unsigned char stn = ntohl(ip->saddr) & 0xff;	struct sock *sk;	struct sk_buff *newskb;	struct ec_device *edev = skb->dev->ec_ptr;	if (! edev)		goto bad;	if ((sk = ec_listening_socket(ah->port, stn, edev->net)) == NULL)		goto bad;		/* Nobody wants it */	newskb = alloc_skb((len - sizeof(struct aunhdr) + 15) & ~15, 			   GFP_ATOMIC);	if (newskb == NULL)	{		printk(KERN_DEBUG "AUN: memory squeeze, dropping packet.\n");		/* Send nack and hope sender tries again */		goto bad;	}	memcpy(skb_put(newskb, len - sizeof(struct aunhdr)), (void *)(ah+1), 	       len - sizeof(struct aunhdr));	if (ec_queue_packet(sk, newskb, stn, edev->net, ah->cb, ah->port))	{		/* Socket is bankrupt. */		kfree_skb(newskb);		goto bad;	}	aun_send_response(ip->saddr, ah->handle, 3, 0);	return;bad:	aun_send_response(ip->saddr, ah->handle, 4, 0);}/* *	Handle incoming AUN transmit acknowledgements.  If the sequence *      number matches something in our backlog then kill it and tell *	the user.  If the remote took too long to reply then we may have *	dropped the packet already. */static void aun_tx_ack(unsigned long seq, int result){	struct sk_buff *skb;	unsigned long flags;	struct ec_cb *eb;	spin_lock_irqsave(&aun_queue_lock, flags);	skb = skb_peek(&aun_queue);	while (skb && skb != (struct sk_buff *)&aun_queue)	{		struct sk_buff *newskb = skb->next;		eb = (struct ec_cb *)&skb->cb;		if (eb->seq == seq)			goto foundit;		skb = newskb;	}	spin_unlock_irqrestore(&aun_queue_lock, flags);	printk(KERN_DEBUG "AUN: unknown sequence %ld\n", seq);	return;foundit:	tx_result(skb->sk, eb->cookie, result);	skb_unlink(skb);	spin_unlock_irqrestore(&aun_queue_lock, flags);	kfree_skb(skb);}/* *	Deal with received AUN frames - sort out what type of thing it is *	and hand it to the right function. */static void aun_data_available(struct sock *sk, int slen){	int err;	struct sk_buff *skb;	unsigned char *data;	struct aunhdr *ah;	struct iphdr *ip;	size_t len;	while ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) {		if (err == -EAGAIN) {			printk(KERN_ERR "AUN: no data available?!");			return;		}		printk(KERN_DEBUG "AUN: recvfrom() error %d\n", -err);	}	data = skb->h.raw + sizeof(struct udphdr);	ah = (struct aunhdr *)data;	len = skb->len - sizeof(struct udphdr);	ip = skb->nh.iph;	switch (ah->code)	{	case 2:		aun_incoming(skb, ah, len);		break;	case 3:		aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_OK);		break;	case 4:		aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_NOT_LISTENING);		break;#if 0		/* This isn't quite right yet. */	case 5:		aun_send_response(ip->saddr, ah->handle, 6, ah->cb);		break;#endif	default:		printk(KERN_DEBUG "unknown AUN packet (type %d)\n", data[0]);	}	skb_free_datagram(sk, skb);}/* *	Called by the timer to manage the AUN transmit queue.  If a packet *	was sent to a dead or nonexistent host then we will never get an *	acknowledgement back.  After a few seconds we need to spot this and *	drop the packet. */static void ab_cleanup(unsigned long h){	struct sk_buff *skb;	unsigned long flags;	spin_lock_irqsave(&aun_queue_lock, flags);	skb = skb_peek(&aun_queue);	while (skb && skb != (struct sk_buff *)&aun_queue)	{		struct sk_buff *newskb = skb->next;		struct ec_cb *eb = (struct ec_cb *)&skb->cb;		if ((jiffies - eb->start) > eb->timeout)		{			tx_result(skb->sk, eb->cookie, 				  ECTYPE_TRANSMIT_NOT_PRESENT);			skb_unlink(skb);			kfree_skb(skb);		}		skb = newskb;	}	spin_unlock_irqrestore(&aun_queue_lock, flags);	mod_timer(&ab_cleanup_timer, jiffies + (HZ*2));}static int __init aun_udp_initialise(void){	int error;	struct sockaddr_in sin;	skb_queue_head_init(&aun_queue);	spin_lock_init(&aun_queue_lock);	init_timer(&ab_cleanup_timer);	ab_cleanup_timer.expires = jiffies + (HZ*2);	ab_cleanup_timer.function = ab_cleanup;	add_timer(&ab_cleanup_timer);	memset(&sin, 0, sizeof(sin));	sin.sin_port = htons(AUN_PORT);	/* We can count ourselves lucky Acorn machines are too dim to	   speak IPv6. :-) */	if ((error = sock_create(PF_INET, SOCK_DGRAM, 0, &udpsock)) < 0)	{		printk("AUN: socket error %d\n", -error);		return error;	}		udpsock->sk->reuse = 1;	udpsock->sk->allocation = GFP_ATOMIC;	/* we're going to call it						   from interrupts */		error = udpsock->ops->bind(udpsock, (struct sockaddr *)&sin,				sizeof(sin));	if (error < 0)	{		printk("AUN: bind error %d\n", -error);		goto release;	}	udpsock->sk->data_ready = aun_data_available;	return 0;release:	sock_release(udpsock);	udpsock = NULL;	return error;}#endif#ifdef CONFIG_ECONET_NATIVE/* *	Receive an Econet frame from a device. */static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt){	struct ec_framehdr *hdr = (struct ec_framehdr *)skb->data;	struct sock *sk;	struct ec_device *edev = dev->ec_ptr;	if (! edev)	{		kfree_skb(skb);		return 0;	}	if (skb->len < sizeof(struct ec_framehdr))	{		/* Frame is too small to be any use */		kfree_skb(skb);		return 0;	}	/* First check for encapsulated IP */	if (hdr->port == EC_PORT_IP)	{		skb->protocol = htons(ETH_P_IP);		skb_pull(skb, sizeof(struct ec_framehdr));		netif_rx(skb);		return 0;	}	sk = ec_listening_socket(hdr->port, hdr->src_stn, hdr->src_net);	if (!sk) 	{		kfree_skb(skb);		return 0;	}	return ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb, 			       hdr->port);}static struct packet_type econet_packet_type = {	type:		__constant_htons(ETH_P_ECONET),	func:		econet_rcv,};static void econet_hw_initialise(void){	dev_add_pack(&econet_packet_type);}#endifstatic int econet_notifier(struct notifier_block *this, unsigned long msg, void *data){	struct net_device *dev = (struct net_device *)data;	struct ec_device *edev;	switch (msg) {	case NETDEV_UNREGISTER:		/* A device has gone down - kill any data we hold for it. */		edev = dev->ec_ptr;		if (edev)		{			if (net2dev_map[0] == dev)				net2dev_map[0] = 0;			net2dev_map[edev->net] = NULL;			kfree(edev);			dev->ec_ptr = NULL;		}		break;	}	return NOTIFY_DONE;}static struct notifier_block econet_netdev_notifier = {	notifier_call:	econet_notifier,};static void __exit econet_proto_exit(void){#ifdef CONFIG_ECONET_AUNUDP	del_timer(&ab_cleanup_timer);	if (udpsock)		sock_release(udpsock);#endif	unregister_netdevice_notifier(&econet_netdev_notifier);	sock_unregister(econet_family_ops.family);}static int __init econet_proto_init(void){	sock_register(&econet_family_ops);#ifdef CONFIG_ECONET_AUNUDP	spin_lock_init(&aun_queue_lock);	aun_udp_initialise();#endif#ifdef CONFIG_ECONET_NATIVE	econet_hw_initialise();#endif	register_netdevice_notifier(&econet_netdev_notifier);	return 0;}module_init(econet_proto_init);module_exit(econet_proto_exit);

⌨️ 快捷键说明

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