📄 af_ipx.c
字号:
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 + -