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

📄 af_ipx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		rc = -EAGAIN;		if (!intrfc)			goto out_dev;		/* Setup primary if necessary */		if (idef->ipx_special == IPX_PRIMARY)			ipx_primary_net = intrfc;		if (!memcmp(idef->ipx_node, "\000\000\000\000\000\000",			    IPX_NODE_LEN)) {			memset(intrfc->if_node, 0, IPX_NODE_LEN);			memcpy(intrfc->if_node + IPX_NODE_LEN - dev->addr_len,				dev->dev_addr, dev->addr_len);		} else			memcpy(intrfc->if_node, idef->ipx_node, IPX_NODE_LEN);		ipxitf_hold(intrfc);		ipxitf_insert(intrfc);	}	/* If the network number is known, add a route */	rc = 0;	if (!intrfc->if_netnum)		goto out_intrfc;	rc = ipxitf_add_local_route(intrfc);out_intrfc:	ipxitf_put(intrfc);	goto out;out_dev:	dev_put(dev);out:	return rc;}static int ipxitf_delete(struct ipx_interface_definition *idef){	struct net_device *dev = NULL;	__be16 dlink_type = 0;	struct ipx_interface *intrfc;	int rc = 0;	spin_lock_bh(&ipx_interfaces_lock);	if (idef->ipx_special == IPX_INTERNAL) {		if (ipx_internal_net) {			__ipxitf_put(ipx_internal_net);			goto out;		}		rc = -ENOENT;		goto out;	}	dlink_type = ipx_map_frame_type(idef->ipx_dlink_type);	rc = -EPROTONOSUPPORT;	if (!dlink_type)		goto out;	dev = __dev_get_by_name(&init_net, idef->ipx_device);	rc = -ENODEV;	if (!dev)		goto out;	intrfc = __ipxitf_find_using_phys(dev, dlink_type);	rc = -EINVAL;	if (!intrfc)		goto out;	__ipxitf_put(intrfc);	rc = 0;out:	spin_unlock_bh(&ipx_interfaces_lock);	return rc;}static struct ipx_interface *ipxitf_auto_create(struct net_device *dev,						__be16 dlink_type){	struct ipx_interface *intrfc = NULL;	struct datalink_proto *datalink;	if (!dev)		goto out;	/* Check addresses are suitable */	if (dev->addr_len > IPX_NODE_LEN)		goto out;	switch (ntohs(dlink_type)) {	case ETH_P_IPX:		datalink = pEII_datalink;	break;	case ETH_P_802_2:	datalink = p8022_datalink;	break;	case ETH_P_SNAP:	datalink = pSNAP_datalink;	break;	case ETH_P_802_3:	datalink = p8023_datalink;	break;	default:		goto out;	}	intrfc = ipxitf_alloc(dev, 0, dlink_type, datalink, 0,				dev->hard_header_len + datalink->header_length);	if (intrfc) {		memset(intrfc->if_node, 0, IPX_NODE_LEN);		memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]),			dev->dev_addr, dev->addr_len);		spin_lock_init(&intrfc->if_sklist_lock);		atomic_set(&intrfc->refcnt, 1);		ipxitf_insert(intrfc);		dev_hold(dev);	}out:	return intrfc;}static int ipxitf_ioctl(unsigned int cmd, void __user *arg){	int rc = -EINVAL;	struct ifreq ifr;	int val;	switch (cmd) {	case SIOCSIFADDR: {		struct sockaddr_ipx *sipx;		struct ipx_interface_definition f;		rc = -EFAULT;		if (copy_from_user(&ifr, arg, sizeof(ifr)))			break;		sipx = (struct sockaddr_ipx *)&ifr.ifr_addr;		rc = -EINVAL;		if (sipx->sipx_family != AF_IPX)			break;		f.ipx_network = sipx->sipx_network;		memcpy(f.ipx_device, ifr.ifr_name,			sizeof(f.ipx_device));		memcpy(f.ipx_node, sipx->sipx_node, IPX_NODE_LEN);		f.ipx_dlink_type = sipx->sipx_type;		f.ipx_special = sipx->sipx_special;		if (sipx->sipx_action == IPX_DLTITF)			rc = ipxitf_delete(&f);		else			rc = ipxitf_create(&f);		break;	}	case SIOCGIFADDR: {		struct sockaddr_ipx *sipx;		struct ipx_interface *ipxif;		struct net_device *dev;		rc = -EFAULT;		if (copy_from_user(&ifr, arg, sizeof(ifr)))			break;		sipx = (struct sockaddr_ipx *)&ifr.ifr_addr;		dev  = __dev_get_by_name(&init_net, ifr.ifr_name);		rc   = -ENODEV;		if (!dev)			break;		ipxif = ipxitf_find_using_phys(dev,					   ipx_map_frame_type(sipx->sipx_type));		rc = -EADDRNOTAVAIL;		if (!ipxif)			break;		sipx->sipx_family	= AF_IPX;		sipx->sipx_network	= ipxif->if_netnum;		memcpy(sipx->sipx_node, ipxif->if_node,			sizeof(sipx->sipx_node));		rc = -EFAULT;		if (copy_to_user(arg, &ifr, sizeof(ifr)))			break;		ipxitf_put(ipxif);		rc = 0;		break;	}	case SIOCAIPXITFCRT:		rc = -EFAULT;		if (get_user(val, (unsigned char __user *) arg))			break;		rc = 0;		ipxcfg_auto_create_interfaces = val;		break;	case SIOCAIPXPRISLT:		rc = -EFAULT;		if (get_user(val, (unsigned char __user *) arg))			break;		rc = 0;		ipxcfg_set_auto_select(val);		break;	}	return rc;}/* *	Checksum routine for IPX *//* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize *//* This functions should *not* mess with packet contents */__be16 ipx_cksum(struct ipxhdr *packet, int length){	/*	 *	NOTE: sum is a net byte order quantity, which optimizes the	 *	loop. This only works on big and little endian machines. (I	 *	don't know of a machine that isn't.)	 */	/* handle the first 3 words separately; checksum should be skipped	 * and ipx_tctrl masked out */	__u16 *p = (__u16 *)packet;	__u32 sum = p[1] + (p[2] & (__force u16)htons(0x00ff));	__u32 i = (length >> 1) - 3; /* Number of remaining complete words */	/* Loop through them */	p += 3;	while (i--)		sum += *p++;	/* Add on the last part word if it exists */	if (packet->ipx_pktsize & htons(1))		sum += (__force u16)htons(0xff00) & *p;	/* Do final fixup */	sum = (sum & 0xffff) + (sum >> 16);	/* It's a pity there's no concept of carry in C */	if (sum >= 0x10000)		sum++;	/*	 * Leave 0 alone; we don't want 0xffff here.  Note that we can't get	 * here with 0x10000, so this check is the same as ((__u16)sum)	 */	if (sum)		sum = ~sum;	return (__force __be16)sum;}const char *ipx_frame_name(__be16 frame){	char* rc = "None";	switch (ntohs(frame)) {	case ETH_P_IPX:		rc = "EtherII";	break;	case ETH_P_802_2:	rc = "802.2";	break;	case ETH_P_SNAP:	rc = "SNAP";	break;	case ETH_P_802_3:	rc = "802.3";	break;	case ETH_P_TR_802_2:	rc = "802.2TR";	break;	}	return rc;}const char *ipx_device_name(struct ipx_interface *intrfc){	return intrfc->if_internal ? "Internal" :		intrfc->if_dev ? intrfc->if_dev->name : "Unknown";}/* Handling for system calls applied via the various interfaces to an IPX * socket object. */static int ipx_setsockopt(struct socket *sock, int level, int optname,			  char __user *optval, int optlen){	struct sock *sk = sock->sk;	int opt;	int rc = -EINVAL;	if (optlen != sizeof(int))		goto out;	rc = -EFAULT;	if (get_user(opt, (unsigned int __user *)optval))		goto out;	rc = -ENOPROTOOPT;	if (!(level == SOL_IPX && optname == IPX_TYPE))		goto out;	ipx_sk(sk)->type = opt;	rc = 0;out:	return rc;}static int ipx_getsockopt(struct socket *sock, int level, int optname,	char __user *optval, int __user *optlen){	struct sock *sk = sock->sk;	int val = 0;	int len;	int rc = -ENOPROTOOPT;	if (!(level == SOL_IPX && optname == IPX_TYPE))		goto out;	val = ipx_sk(sk)->type;	rc = -EFAULT;	if (get_user(len, optlen))		goto out;	len = min_t(unsigned int, len, sizeof(int));	rc = -EINVAL;	if(len < 0)		goto out;	rc = -EFAULT;	if (put_user(len, optlen) || copy_to_user(optval, &val, len))		goto out;	rc = 0;out:	return rc;}static struct proto ipx_proto = {	.name	  = "IPX",	.owner	  = THIS_MODULE,	.obj_size = sizeof(struct ipx_sock),};static int ipx_create(struct net *net, struct socket *sock, int protocol){	int rc = -ESOCKTNOSUPPORT;	struct sock *sk;	if (net != &init_net)		return -EAFNOSUPPORT;	/*	 * SPX support is not anymore in the kernel sources. If you want to	 * ressurrect it, completing it and making it understand shared skbs,	 * be fully multithreaded, etc, grab the sources in an early 2.5 kernel	 * tree.	 */	if (sock->type != SOCK_DGRAM)		goto out;	rc = -ENOMEM;	sk = sk_alloc(net, PF_IPX, GFP_KERNEL, &ipx_proto);	if (!sk)		goto out;	sk_refcnt_debug_inc(sk);	sock_init_data(sock, sk);	sk->sk_no_check = 1;		/* Checksum off by default */	sock->ops = &ipx_dgram_ops;	rc = 0;out:	return rc;}static int ipx_release(struct socket *sock){	struct sock *sk = sock->sk;	if (!sk)		goto out;	if (!sock_flag(sk, SOCK_DEAD))		sk->sk_state_change(sk);	sock_set_flag(sk, SOCK_DEAD);	sock->sk = NULL;	sk_refcnt_debug_release(sk);	ipx_destroy_socket(sk);out:	return 0;}/* caller must hold a reference to intrfc */static __be16 ipx_first_free_socketnum(struct ipx_interface *intrfc){	unsigned short socketNum = intrfc->if_sknum;	spin_lock_bh(&intrfc->if_sklist_lock);	if (socketNum < IPX_MIN_EPHEMERAL_SOCKET)		socketNum = IPX_MIN_EPHEMERAL_SOCKET;	while (__ipxitf_find_socket(intrfc, htons(socketNum)))		if (socketNum > IPX_MAX_EPHEMERAL_SOCKET)			socketNum = IPX_MIN_EPHEMERAL_SOCKET;		else			socketNum++;	spin_unlock_bh(&intrfc->if_sklist_lock);	intrfc->if_sknum = socketNum;	return htons(socketNum);}static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sock *sk = sock->sk;	struct ipx_sock *ipxs = ipx_sk(sk);	struct ipx_interface *intrfc;	struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr;	int rc = -EINVAL;	if (!sock_flag(sk, SOCK_ZAPPED) || addr_len != sizeof(struct sockaddr_ipx))		goto out;	intrfc = ipxitf_find_using_net(addr->sipx_network);	rc = -EADDRNOTAVAIL;	if (!intrfc)		goto out;	if (!addr->sipx_port) {		addr->sipx_port = ipx_first_free_socketnum(intrfc);		rc = -EINVAL;		if (!addr->sipx_port)			goto out_put;	}	/* protect IPX system stuff like routing/sap */	rc = -EACCES;	if (ntohs(addr->sipx_port) < IPX_MIN_EPHEMERAL_SOCKET &&	    !capable(CAP_NET_ADMIN))		goto out_put;	ipxs->port = addr->sipx_port;#ifdef CONFIG_IPX_INTERN	if (intrfc == ipx_internal_net) {		/* The source address is to be set explicitly if the		 * socket is to be bound on the internal network. If a		 * node number 0 was specified, the default is used.		 */		rc = -EINVAL;		if (!memcmp(addr->sipx_node, ipx_broadcast_node, IPX_NODE_LEN))			goto out_put;		if (!memcmp(addr->sipx_node, ipx_this_node, IPX_NODE_LEN))			memcpy(ipxs->node, intrfc->if_node, IPX_NODE_LEN);		else			memcpy(ipxs->node, addr->sipx_node, IPX_NODE_LEN);		rc = -EADDRINUSE;		if (ipxitf_find_internal_socket(intrfc, ipxs->node,						ipxs->port)) {			SOCK_DEBUG(sk,				"IPX: bind failed because port %X in use.\n",				ntohs(addr->sipx_port));			goto out_put;		}	} else {		/* Source addresses are easy. It must be our		 * network:node pair for an interface routed to IPX		 * with the ipx routing ioctl()		 */		memcpy(ipxs->node, intrfc->if_node, IPX_NODE_LEN);		rc = -EADDRINUSE;		if (ipxitf_find_socket(intrfc, addr->sipx_port)) {			SOCK_DEBUG(sk,				"IPX: bind failed because port %X in use.\n",				ntohs(addr->sipx_port));			goto out_put;		}	}#else	/* !def CONFIG_IPX_INTERN */	/* Source addresses are easy. It must be our network:node pair for	   an interface routed to IPX with the ipx routing ioctl() */	rc = -EADDRINUSE;	if (ipxitf_find_socket(intrfc, addr->sipx_port)) {		SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n",				ntohs((int)addr->sipx_port));		goto out_put;	}#endif	/* CONFIG_IPX_INTERN */	ipxitf_insert_socket(intrfc, sk);	sock_reset_flag(sk, SOCK_ZAPPED);	rc = 0;out_put:	ipxitf_put(intrfc);out:	return rc;}static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,	int addr_len, int flags){	struct sock *sk = sock->sk;	struct ipx_sock *ipxs = ipx_sk(sk);	struct sockaddr_ipx *addr;	int rc = -EINVAL;	struct ipx_route *rt;	sk->sk_state	= TCP_CLOSE;	sock->state 	= SS_UNCONNECTED;	if (addr_len != sizeof(*addr))		goto out;	addr = (struct sockaddr_ipx *)uaddr;	/* put the autobinding in */	if (!ipxs->port) {		struct sockaddr_ipx uaddr;		uaddr.sipx_port		= 0;		uaddr.sipx_network 	= 0;#ifdef CONFIG_IPX_INTERN		rc = -ENETDOWN;		if (!ipxs->intrfc)			goto out; /* Someone zonked the iface */		memcpy(uaddr.sipx_node, ipxs->intrfc->if_node,

⌨️ 快捷键说明

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