📄 af_ipx.c
字号:
skb->sk = sk; /* Fill in IPX header */ ipx = (struct ipxhdr *)skb_put(skb, sizeof(struct ipxhdr)); ipx->ipx_pktsize = htons(len + sizeof(struct ipxhdr)); IPX_SKB_CB(skb)->ipx_tctrl = 0; ipx->ipx_type = usipx->sipx_type; skb->h.raw = (void *)skb->nh.ipxh = ipx; IPX_SKB_CB(skb)->last_hop.index = -1;#ifdef CONFIG_IPX_INTERN IPX_SKB_CB(skb)->ipx_source_net = sk->protinfo.af_ipx.intrfc->if_netnum; memcpy(ipx->ipx_source.node, sk->protinfo.af_ipx.node, IPX_NODE_LEN);#else err = ntohs(sk->protinfo.af_ipx.port); if (err == 0x453 || err == 0x452) { /* RIP/SAP special handling for mars_nwe */ IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum; memcpy(ipx->ipx_source.node, intrfc->if_node, IPX_NODE_LEN); } else { IPX_SKB_CB(skb)->ipx_source_net = sk->protinfo.af_ipx.intrfc->if_netnum; memcpy(ipx->ipx_source.node, sk->protinfo.af_ipx.intrfc->if_node, IPX_NODE_LEN); }#endif /* CONFIG_IPX_INTERN */ ipx->ipx_source.sock = sk->protinfo.af_ipx.port; IPX_SKB_CB(skb)->ipx_dest_net = usipx->sipx_network; memcpy(ipx->ipx_dest.node, usipx->sipx_node, IPX_NODE_LEN); ipx->ipx_dest.sock = usipx->sipx_port; err = memcpy_fromiovec(skb_put(skb, len), iov, len); if (err) { kfree_skb(skb); goto out_put; } /* Apply checksum. Not allowed on 802.3 links. */ if (sk->no_check || intrfc->if_dlink_type == IPX_FRAME_8023) ipx->ipx_checksum = 0xFFFF; else ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr)); err = ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? rt->ir_router_node : ipx->ipx_dest.node);out_put: ipxitf_put(intrfc); if (rt) ipxrtr_put(rt);out: return err;}/* the skb has to be unshared, we'll end up calling ipxitf_send, that'll * modify the packet */int ipxrtr_route_skb(struct sk_buff *skb){ struct ipxhdr *ipx = skb->nh.ipxh; ipx_route *r = ipxrtr_lookup(IPX_SKB_CB(skb)->ipx_dest_net); if (!r) { /* no known route */ kfree_skb(skb); return 0; } ipxitf_hold(r->ir_intrfc); ipxitf_send(r->ir_intrfc, skb, r->ir_routed ? r->ir_router_node : ipx->ipx_dest.node); ipxitf_put(r->ir_intrfc); ipxrtr_put(r); return 0;}/* * We use a normal struct rtentry for route handling */static int ipxrtr_ioctl(unsigned int cmd, void *arg){ struct rtentry rt; /* Use these to behave like 'other' stacks */ struct sockaddr_ipx *sg, *st; int ret = -EFAULT; if (copy_from_user(&rt, arg, sizeof(rt))) goto out; sg = (struct sockaddr_ipx *)&rt.rt_gateway; st = (struct sockaddr_ipx *)&rt.rt_dst; ret = -EINVAL; if (!(rt.rt_flags & RTF_GATEWAY) || /* Direct routes are fixed */ sg->sipx_family != AF_IPX || st->sipx_family != AF_IPX) goto out; switch (cmd) { case SIOCDELRT: ret = ipxrtr_delete(st->sipx_network); break; case SIOCADDRT: { struct ipx_route_definition f; f.ipx_network = st->sipx_network; f.ipx_router_network = sg->sipx_network; memcpy(f.ipx_router_node, sg->sipx_node, IPX_NODE_LEN); ret = ipxrtr_create(&f); break; } }out: return ret;}static const char *ipx_frame_name(unsigned short frame){ char* ret = "None"; switch (ntohs(frame)) { case ETH_P_IPX: ret = "EtherII"; break; case ETH_P_802_2: ret = "802.2"; break; case ETH_P_SNAP: ret = "SNAP"; break; case ETH_P_802_3: ret = "802.3"; break; case ETH_P_TR_802_2: ret = "802.2TR"; break; } return ret;}static const char *ipx_device_name(ipx_interface *intrfc){ return intrfc->if_internal ? "Internal" : intrfc->if_dev ? intrfc->if_dev->name : "Unknown";}/* Called from proc fs */static int ipx_interface_get_info(char *buffer, char **start, off_t offset, int length){ ipx_interface *i; off_t begin = 0, pos = 0; int len = 0; /* Theory.. Keep printing in the same place until we pass offset */ len += sprintf(buffer, "%-11s%-15s%-9s%-11s%s", "Network", "Node_Address", "Primary", "Device", "Frame_Type");#ifdef IPX_REFCNT_DEBUG len += sprintf(buffer + len, " refcnt");#endif strcat(buffer + len++, "\n"); spin_lock_bh(&ipx_interfaces_lock); for (i = ipx_interfaces; i; i = i->if_next) { len += sprintf(buffer + len, "%08lX ", (long unsigned int) ntohl(i->if_netnum)); len += sprintf(buffer + len, "%02X%02X%02X%02X%02X%02X ", i->if_node[0], i->if_node[1], i->if_node[2], i->if_node[3], i->if_node[4], i->if_node[5]); len += sprintf(buffer + len, "%-9s", i == ipx_primary_net ? "Yes" : "No"); len += sprintf(buffer + len, "%-11s", ipx_device_name(i)); len += sprintf(buffer + len, "%-9s", ipx_frame_name(i->if_dlink_type));#ifdef IPX_REFCNT_DEBUG len += sprintf(buffer + len, "%6d", atomic_read(&i->refcnt));#endif strcat(buffer + len++, "\n"); /* Are we still dumping unwanted data then discard the record */ pos = begin + len; if (pos < offset) { len = 0; /* Keep dumping into the buffer start */ begin = pos; } if (pos > offset + length) /* We have dumped enough */ break; } spin_unlock_bh(&ipx_interfaces_lock); /* The data in question runs from begin to begin+len */ *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); /* Remove unwanted header data from length */ if (len > length) len = length; /* Remove unwanted tail data from length */ return len;}static int ipx_get_info(char *buffer, char **start, off_t offset, int length){ struct sock *s; ipx_interface *i; off_t begin = 0, pos = 0; int len = 0; /* Theory.. Keep printing in the same place until we pass offset */#ifdef CONFIG_IPX_INTERN len += sprintf(buffer, "%-28s%-28s%-10s%-10s%-7s%s\n", "Local_Address",#else len += sprintf(buffer, "%-15s%-28s%-10s%-10s%-7s%s\n", "Local_Address",#endif /* CONFIG_IPX_INTERN */ "Remote_Address", "Tx_Queue", "Rx_Queue", "State", "Uid"); spin_lock_bh(&ipx_interfaces_lock); for (i = ipx_interfaces; i; i = i->if_next) { ipxitf_hold(i); spin_lock_bh(&i->if_sklist_lock); for (s = i->if_sklist; s; s = s->next) {#ifdef CONFIG_IPX_INTERN len += sprintf(buffer + len, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", (unsigned long) htonl(s->protinfo.af_ipx.intrfc->if_netnum), s->protinfo.af_ipx.node[0], s->protinfo.af_ipx.node[1], s->protinfo.af_ipx.node[2], s->protinfo.af_ipx.node[3], s->protinfo.af_ipx.node[4], s->protinfo.af_ipx.node[5], htons(s->protinfo.af_ipx.port));#else len += sprintf(buffer + len, "%08lX:%04X ", (unsigned long) htonl(i->if_netnum), htons(s->protinfo.af_ipx.port));#endif /* CONFIG_IPX_INTERN */ if (s->state != TCP_ESTABLISHED) len += sprintf(buffer + len, "%-28s", "Not_Connected"); else { len += sprintf(buffer + len, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", (unsigned long) htonl(s->protinfo.af_ipx.dest_addr.net), s->protinfo.af_ipx.dest_addr.node[0], s->protinfo.af_ipx.dest_addr.node[1], s->protinfo.af_ipx.dest_addr.node[2], s->protinfo.af_ipx.dest_addr.node[3], s->protinfo.af_ipx.dest_addr.node[4], s->protinfo.af_ipx.dest_addr.node[5], htons(s->protinfo.af_ipx.dest_addr.sock)); } len += sprintf(buffer + len, "%08X %08X ", atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc)); len += sprintf(buffer + len, "%02X %03d\n", s->state, SOCK_INODE(s->socket)->i_uid); pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > offset + length) /* We have dumped enough */ break; } spin_unlock_bh(&i->if_sklist_lock); ipxitf_put(i); } spin_unlock_bh(&ipx_interfaces_lock); /* The data in question runs from begin to begin+len */ *start = buffer + offset - begin; len -= (offset - begin); if (len > length) len = length; return len;}static int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length){ ipx_route *rt; off_t begin = 0, pos = 0; int len = 0; len += sprintf(buffer, "%-11s%-13s%s\n", "Network", "Router_Net", "Router_Node"); read_lock_bh(&ipx_routes_lock); for (rt = ipx_routes; rt; rt = rt->ir_next) { len += sprintf(buffer + len, "%08lX ", (long unsigned int) ntohl(rt->ir_net)); if (rt->ir_routed) { len += sprintf(buffer + len, "%08lX %02X%02X%02X%02X%02X%02X\n", (long unsigned int) ntohl(rt->ir_intrfc->if_netnum), rt->ir_router_node[0], rt->ir_router_node[1], rt->ir_router_node[2], rt->ir_router_node[3], rt->ir_router_node[4], rt->ir_router_node[5]); } else { len += sprintf(buffer + len, "%-13s%s\n", "Directly", "Connected"); } pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > offset + length) break; } read_unlock_bh(&ipx_routes_lock); *start = buffer + (offset - begin); len -= (offset - begin); if (len > length) len = length; return len;}/* 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 *optval, int optlen){ struct sock *sk = sock->sk; int opt; int ret = -EINVAL; if (optlen != sizeof(int)) goto out; ret = -EFAULT; if (get_user(opt, (unsigned int *)optval)) goto out; ret = -ENOPROTOOPT; if (!(level == SOL_IPX && optname == IPX_TYPE)) goto out; sk->protinfo.af_ipx.type = opt; ret = 0;out: return ret;}static int ipx_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen){ struct sock *sk = sock->sk; int val = 0; int len; int ret = -ENOPROTOOPT; if (!(level == SOL_IPX && optname == IPX_TYPE)) goto out; val = sk->protinfo.af_ipx.type; ret = -EFAULT; if (get_user(len, optlen)) goto out; len = min_t(unsigned int, len, sizeof(int)); ret = -EINVAL; if(len < 0) goto out; ret = -EFAULT; if (put_user(len, optlen) || copy_to_user(optval, &val, len)) goto out; ret = 0;out: return ret;}static int ipx_create(struct socket *sock, int protocol){ int ret = -ESOCKTNOSUPPORT; struct sock *sk; switch (sock->type) { case SOCK_DGRAM: sk = sk_alloc(PF_IPX, GFP_KERNEL, 1); ret = -ENOMEM; if (!sk) goto out; sock->ops = &ipx_dgram_ops; break; case SOCK_SEQPACKET: /* * From this point on SPX sockets are handled * by af_spx.c and the methods replaced. */ if (spx_family_ops) { ret = spx_family_ops->create(sock, protocol); goto out; } /* Fall through if SPX is not loaded */ case SOCK_STREAM: /* Allow higher levels to piggyback */ default: goto out; }#ifdef IPX_REFCNT_DEBUG atomic_inc(&ipx_sock_nr); printk(KERN_DEBUG "IPX socket %p created, now we have %d alive\n", sk, atomic_read(&ipx_sock_nr));#endif sock_init_data(sock, sk); sk->destruct = NULL; sk->no_check = 1; /* Checksum off by default */ MOD_INC_USE_COUNT; ret = 0;out: return ret;}static int ipx_release(struct socket *sock){ struct sock *sk = sock->sk; if (!sk) goto out; if (!sk->dead) sk->state_change(sk); sk->dead = 1; sock->sk = NULL; ipx_destroy_socket(sk); if (sock->type == SOCK_DGRAM) MOD_DEC_USE_COUNT;out: return 0;}/* caller must hold a reference to intrfc */static unsigned short ipx_first_free_socketnum(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, ntohs(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 ntohs(socketNum);}static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){ struct sock *sk = sock->sk; ipx_interface *intrfc; struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr; int ret = -EINVAL; if (!sk->zapped || addr_len != sizeof(struct sockaddr_ipx)) goto out; intrfc = ipxitf_find_using_net(addr->sipx_network); ret = -EADDRNOTAVAIL; if (!intrfc) goto out; if (!addr->sipx_port) { addr->sipx_port = ipx_first_free_socketnum(intrfc); ret = -EINVAL; if (!addr->sipx_port) goto out_put; } /* protect IPX system stuff like routing/sap */ ret = -EACCES; if (ntohs(addr->sipx_port) < IPX_MIN_EPHEMERAL_SOCKET && !capable(CAP_NET_ADMIN)) goto out_put; sk->protinfo.af_ipx.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. */ ret = -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(sk->protinfo.af_ipx.node, intrfc->if_node, IPX_NODE_LEN); else memcpy(sk->protinfo.af_ipx.node, addr->sipx_node, IPX_NODE_LEN); ret = -EADDRINUSE; if (ipxitf_find_internal_socket(intrfc, sk->protinfo.af_ipx.node, sk->protinfo.af_ipx.port)) { SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", ntohs((int)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() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -