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

📄 ddp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		goto out;	}	/* if IP over DDP is not selected this code will be optimized out */	if (is_ip_over_ddp(skb))		return handle_ip_over_ddp(skb);	/*	 * Which socket - atalk_search_socket() looks for a *full match*	 * of the <net, node, port> tuple.	 */	tosat.sat_addr.s_net  = ddp->deh_dnet;	tosat.sat_addr.s_node = ddp->deh_dnode;	tosat.sat_port	      = ddp->deh_dport;	sock = atalk_search_socket(&tosat, atif);	if (!sock) /* But not one of our sockets */		goto freeit;	/* Queue packet (standard) */	skb->sk = sock;	if (sock_queue_rcv_skb(sock, skb) < 0)		goto freeit;out:	return 0;freeit:	kfree_skb(skb);	goto out;}/* * Receive a LocalTalk frame. We make some demands on the caller here. * Caller must provide enough headroom on the packet to pull the short * header and append a long one. */static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,		     struct packet_type *pt, struct net_device *orig_dev){	if (dev->nd_net != &init_net)		goto freeit;	/* Expand any short form frames */	if (skb_mac_header(skb)[2] == 1) {		struct ddpehdr *ddp;		/* Find our address */		struct atalk_addr *ap = atalk_find_dev_addr(dev);		if (!ap || skb->len < sizeof(__be16) || skb->len > 1023)			goto freeit;		/* Don't mangle buffer if shared */		if (!(skb = skb_share_check(skb, GFP_ATOMIC)))			return 0;		/*		 * The push leaves us with a ddephdr not an shdr, and		 * handily the port bytes in the right place preset.		 */		ddp = (struct ddpehdr *) skb_push(skb, sizeof(*ddp) - 4);		/* Now fill in the long header */		/*		 * These two first. The mac overlays the new source/dest		 * network information so we MUST copy these before		 * we write the network numbers !		 */		ddp->deh_dnode = skb_mac_header(skb)[0];     /* From physical header */		ddp->deh_snode = skb_mac_header(skb)[1];     /* From physical header */		ddp->deh_dnet  = ap->s_net;	/* Network number */		ddp->deh_snet  = ap->s_net;		ddp->deh_sum   = 0;		/* No checksum */		/*		 * Not sure about this bit...		 */		/* Non routable, so force a drop if we slip up later */		ddp->deh_len_hops = htons(skb->len + (DDP_MAXHOPS << 10));	}	skb_reset_transport_header(skb);	return atalk_rcv(skb, dev, pt, orig_dev);freeit:	kfree_skb(skb);	return 0;}static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,			 size_t len){	struct sock *sk = sock->sk;	struct atalk_sock *at = at_sk(sk);	struct sockaddr_at *usat = (struct sockaddr_at *)msg->msg_name;	int flags = msg->msg_flags;	int loopback = 0;	struct sockaddr_at local_satalk, gsat;	struct sk_buff *skb;	struct net_device *dev;	struct ddpehdr *ddp;	int size;	struct atalk_route *rt;	int err;	if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))		return -EINVAL;	if (len > DDP_MAXSZ)		return -EMSGSIZE;	if (usat) {		if (sock_flag(sk, SOCK_ZAPPED))			if (atalk_autobind(sk) < 0)				return -EBUSY;		if (msg->msg_namelen < sizeof(*usat) ||		    usat->sat_family != AF_APPLETALK)			return -EINVAL;		/* netatalk doesn't implement this check */		if (usat->sat_addr.s_node == ATADDR_BCAST &&		    !sock_flag(sk, SOCK_BROADCAST)) {			printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as "					 "it will break before 2.2\n");#if 0			return -EPERM;#endif		}	} else {		if (sk->sk_state != TCP_ESTABLISHED)			return -ENOTCONN;		usat = &local_satalk;		usat->sat_family      = AF_APPLETALK;		usat->sat_port	      = at->dest_port;		usat->sat_addr.s_node = at->dest_node;		usat->sat_addr.s_net  = at->dest_net;	}	/* Build a packet */	SOCK_DEBUG(sk, "SK %p: Got address.\n", sk);	/* For headers */	size = sizeof(struct ddpehdr) + len + ddp_dl->header_length;	if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) {		rt = atrtr_find(&usat->sat_addr);	} else {		struct atalk_addr at_hint;		at_hint.s_node = 0;		at_hint.s_net  = at->src_net;		rt = atrtr_find(&at_hint);	}	if (!rt)		return -ENETUNREACH;	dev = rt->dev;	SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n",			sk, size, dev->name);	size += dev->hard_header_len;	skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err);	if (!skb)		return err;	skb->sk = sk;	skb_reserve(skb, ddp_dl->header_length);	skb_reserve(skb, dev->hard_header_len);	skb->dev = dev;	SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);	ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr));	ddp->deh_len_hops  = htons(len + sizeof(*ddp));	ddp->deh_dnet  = usat->sat_addr.s_net;	ddp->deh_snet  = at->src_net;	ddp->deh_dnode = usat->sat_addr.s_node;	ddp->deh_snode = at->src_node;	ddp->deh_dport = usat->sat_port;	ddp->deh_sport = at->src_port;	SOCK_DEBUG(sk, "SK %p: Copy user data (%Zd bytes).\n", sk, len);	err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);	if (err) {		kfree_skb(skb);		return -EFAULT;	}	if (sk->sk_no_check == 1)		ddp->deh_sum = 0;	else		ddp->deh_sum = atalk_checksum(skb, len + sizeof(*ddp));	/*	 * Loopback broadcast packets to non gateway targets (ie routes	 * to group we are in)	 */	if (ddp->deh_dnode == ATADDR_BCAST &&	    !(rt->flags & RTF_GATEWAY) && !(dev->flags & IFF_LOOPBACK)) {		struct sk_buff *skb2 = skb_copy(skb, GFP_KERNEL);		if (skb2) {			loopback = 1;			SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk);			if (aarp_send_ddp(dev, skb2,					  &usat->sat_addr, NULL) == -1)				kfree_skb(skb2);				/* else queued/sent above in the aarp queue */		}	}	if (dev->flags & IFF_LOOPBACK || loopback) {		SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk);		/* loop back */		skb_orphan(skb);		if (ddp->deh_dnode == ATADDR_BCAST) {			struct atalk_addr at_lo;			at_lo.s_node = 0;			at_lo.s_net  = 0;			rt = atrtr_find(&at_lo);			if (!rt) {				kfree_skb(skb);				return -ENETUNREACH;			}			dev = rt->dev;			skb->dev = dev;		}		ddp_dl->request(ddp_dl, skb, dev->dev_addr);	} else {		SOCK_DEBUG(sk, "SK %p: send out.\n", sk);		if (rt->flags & RTF_GATEWAY) {		    gsat.sat_addr = rt->gateway;		    usat = &gsat;		}		if (aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1)			kfree_skb(skb);		/* else queued/sent above in the aarp queue */	}	SOCK_DEBUG(sk, "SK %p: Done write (%Zd).\n", sk, len);	return len;}static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,			 size_t size, int flags){	struct sock *sk = sock->sk;	struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;	struct ddpehdr *ddp;	int copied = 0;	int offset = 0;	int err = 0;	struct sk_buff *skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,						flags & MSG_DONTWAIT, &err);	if (!skb)		return err;	/* FIXME: use skb->cb to be able to use shared skbs */	ddp = ddp_hdr(skb);	copied = ntohs(ddp->deh_len_hops) & 1023;	if (sk->sk_type != SOCK_RAW) {		offset = sizeof(*ddp);		copied -= offset;	}	if (copied > size) {		copied = size;		msg->msg_flags |= MSG_TRUNC;	}	err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);	if (!err) {		if (sat) {			sat->sat_family      = AF_APPLETALK;			sat->sat_port        = ddp->deh_sport;			sat->sat_addr.s_node = ddp->deh_snode;			sat->sat_addr.s_net  = ddp->deh_snet;		}		msg->msg_namelen = sizeof(*sat);	}	skb_free_datagram(sk, skb);	/* Free the datagram. */	return err ? : copied;}/* * AppleTalk ioctl calls. */static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	int rc = -ENOIOCTLCMD;	struct sock *sk = sock->sk;	void __user *argp = (void __user *)arg;	switch (cmd) {		/* Protocol layer */		case TIOCOUTQ: {			long amount = sk->sk_sndbuf -				      atomic_read(&sk->sk_wmem_alloc);			if (amount < 0)				amount = 0;			rc = put_user(amount, (int __user *)argp);			break;		}		case TIOCINQ: {			/*			 * These two are safe on a single CPU system as only			 * user tasks fiddle here			 */			struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);			long amount = 0;			if (skb)				amount = skb->len - sizeof(struct ddpehdr);			rc = put_user(amount, (int __user *)argp);			break;		}		case SIOCGSTAMP:			rc = sock_get_timestamp(sk, argp);			break;		case SIOCGSTAMPNS:			rc = sock_get_timestampns(sk, argp);			break;		/* Routing */		case SIOCADDRT:		case SIOCDELRT:			rc = -EPERM;			if (capable(CAP_NET_ADMIN))				rc = atrtr_ioctl(cmd, argp);			break;		/* Interface */		case SIOCGIFADDR:		case SIOCSIFADDR:		case SIOCGIFBRDADDR:		case SIOCATALKDIFADDR:		case SIOCDIFADDR:		case SIOCSARP:		/* proxy AARP */		case SIOCDARP:		/* proxy AARP */			rtnl_lock();			rc = atif_ioctl(cmd, argp);			rtnl_unlock();			break;	}	return rc;}#ifdef CONFIG_COMPATstatic int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	/*	 * All Appletalk ioctls except SIOCATALKDIFADDR are standard.  And	 * SIOCATALKDIFADDR is handled by upper layer as well, so there is	 * nothing to do.  Eventually SIOCATALKDIFADDR should be moved	 * here so there is no generic SIOCPROTOPRIVATE translation in the	 * system.	 */	return -ENOIOCTLCMD;}#endifstatic struct net_proto_family atalk_family_ops = {	.family		= PF_APPLETALK,	.create		= atalk_create,	.owner		= THIS_MODULE,};static const struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = {	.family		= PF_APPLETALK,	.owner		= THIS_MODULE,	.release	= atalk_release,	.bind		= atalk_bind,	.connect	= atalk_connect,	.socketpair	= sock_no_socketpair,	.accept		= sock_no_accept,	.getname	= atalk_getname,	.poll		= datagram_poll,	.ioctl		= atalk_ioctl,#ifdef CONFIG_COMPAT	.compat_ioctl	= atalk_compat_ioctl,#endif	.listen		= sock_no_listen,	.shutdown	= sock_no_shutdown,	.setsockopt	= sock_no_setsockopt,	.getsockopt	= sock_no_getsockopt,	.sendmsg	= atalk_sendmsg,	.recvmsg	= atalk_recvmsg,	.mmap		= sock_no_mmap,	.sendpage	= sock_no_sendpage,};SOCKOPS_WRAP(atalk_dgram, PF_APPLETALK);static struct notifier_block ddp_notifier = {	.notifier_call	= ddp_device_event,};static struct packet_type ltalk_packet_type = {	.type		= __constant_htons(ETH_P_LOCALTALK),	.func		= ltalk_rcv,};static struct packet_type ppptalk_packet_type = {	.type		= __constant_htons(ETH_P_PPPTALK),	.func		= atalk_rcv,};static unsigned char ddp_snap_id[] = { 0x08, 0x00, 0x07, 0x80, 0x9B };/* Export symbols for use by drivers when AppleTalk is a module */EXPORT_SYMBOL(aarp_send_ddp);EXPORT_SYMBOL(atrtr_get_dev);EXPORT_SYMBOL(atalk_find_dev_addr);static char atalk_err_snap[] __initdata =	KERN_CRIT "Unable to register DDP with SNAP.\n";/* Called by proto.c on kernel start up */static int __init atalk_init(void){	int rc = proto_register(&ddp_proto, 0);	if (rc != 0)		goto out;	(void)sock_register(&atalk_family_ops);	ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv);	if (!ddp_dl)		printk(atalk_err_snap);	dev_add_pack(&ltalk_packet_type);	dev_add_pack(&ppptalk_packet_type);	register_netdevice_notifier(&ddp_notifier);	aarp_proto_init();	atalk_proc_init();	atalk_register_sysctl();out:	return rc;}module_init(atalk_init);/* * No explicit module reference count manipulation is needed in the * protocol. Socket layer sets module reference count for us * and interfaces reference counting is done * by the network device layer. * * Ergo, before the AppleTalk module can be removed, all AppleTalk * sockets be closed from user space. */static void __exit atalk_exit(void){#ifdef CONFIG_SYSCTL	atalk_unregister_sysctl();#endif /* CONFIG_SYSCTL */	atalk_proc_exit();	aarp_cleanup_module();	/* General aarp clean-up. */	unregister_netdevice_notifier(&ddp_notifier);	dev_remove_pack(&ltalk_packet_type);	dev_remove_pack(&ppptalk_packet_type);	unregister_snap_client(ddp_dl);	sock_unregister(PF_APPLETALK);	proto_unregister(&ddp_proto);}module_exit(atalk_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Alan Cox <Alan.Cox@linux.org>");MODULE_DESCRIPTION("AppleTalk 0.20\n");MODULE_ALIAS_NETPROTO(PF_APPLETALK);

⌨️ 快捷键说明

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