📄 af_ipx.c
字号:
if (!intrfc) goto out; memcpy((char *)&(intrfc->if_node), idef->ipx_node, IPX_NODE_LEN); ipx_internal_net = ipx_primary_net = intrfc; ipxitf_hold(intrfc); ipxitf_insert(intrfc); ret = ipxitf_add_local_route(intrfc); ipxitf_put(intrfc);out: return ret;}static int ipx_map_frame_type(unsigned char type){ int ret = 0; switch (type) { case IPX_FRAME_ETHERII: ret = __constant_htons(ETH_P_IPX); break; case IPX_FRAME_8022: ret = __constant_htons(ETH_P_802_2); break; case IPX_FRAME_SNAP: ret = __constant_htons(ETH_P_SNAP); break; case IPX_FRAME_8023: ret = __constant_htons(ETH_P_802_3); break; } return ret;}static int ipxitf_create(ipx_interface_definition *idef){ struct net_device *dev; unsigned short dlink_type = 0; struct datalink_proto *datalink = NULL; ipx_interface *intrfc; int err; if (idef->ipx_special == IPX_INTERNAL) { err = ipxitf_create_internal(idef); goto out; } err = -EEXIST; if (idef->ipx_special == IPX_PRIMARY && ipx_primary_net) goto out; intrfc = ipxitf_find_using_net(idef->ipx_network); err = -EADDRINUSE; if (idef->ipx_network && intrfc) { ipxitf_put(intrfc); goto out; } if (intrfc) ipxitf_put(intrfc); dev = dev_get_by_name(idef->ipx_device); err = -ENODEV; if (!dev) goto out; switch (idef->ipx_dlink_type) { case IPX_FRAME_TR_8022: printk(KERN_WARNING "IPX frame type 802.2TR is " "obsolete Use 802.2 instead.\n"); /* fall through */ case IPX_FRAME_8022: dlink_type = __constant_htons(ETH_P_802_2); datalink = p8022_datalink; break; case IPX_FRAME_ETHERII: if (dev->type != ARPHRD_IEEE802) { dlink_type = __constant_htons(ETH_P_IPX); datalink = pEII_datalink; break; } else printk(KERN_WARNING "IPX frame type EtherII " "over token-ring is obsolete. Use SNAP " "instead.\n"); /* fall through */ case IPX_FRAME_SNAP: dlink_type = __constant_htons(ETH_P_SNAP); datalink = pSNAP_datalink; break; case IPX_FRAME_8023: dlink_type = __constant_htons(ETH_P_802_3); datalink = p8023_datalink; break; case IPX_FRAME_NONE: default: err = -EPROTONOSUPPORT; goto out_dev; } err = -ENETDOWN; if (!(dev->flags & IFF_UP)) goto out_dev; /* Check addresses are suitable */ err = -EINVAL; if (dev->addr_len > IPX_NODE_LEN) goto out_dev; intrfc = ipxitf_find_using_phys(dev, dlink_type); if (!intrfc) { /* Ok now create */ intrfc = ipxitf_alloc(dev, idef->ipx_network, dlink_type, datalink, 0, dev->hard_header_len + datalink->header_length); err = -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 */ err = 0; if (!intrfc->if_netnum) goto out_intrfc; err = ipxitf_add_local_route(intrfc);out_intrfc: ipxitf_put(intrfc); goto out;out_dev: dev_put(dev);out: return err;}static int ipxitf_delete(ipx_interface_definition *idef){ struct net_device *dev = NULL; unsigned short dlink_type = 0; ipx_interface *intrfc; int ret = 0; spin_lock_bh(&ipx_interfaces_lock); if (idef->ipx_special == IPX_INTERNAL) { if (ipx_internal_net) { __ipxitf_put(ipx_internal_net); goto out; } ret = -ENOENT; goto out; } dlink_type = ipx_map_frame_type(idef->ipx_dlink_type); ret = -EPROTONOSUPPORT; if (!dlink_type) goto out; dev = __dev_get_by_name(idef->ipx_device); ret = -ENODEV; if (!dev) goto out; intrfc = __ipxitf_find_using_phys(dev, dlink_type); ret = -EINVAL; if (!intrfc) goto out; __ipxitf_put(intrfc); ret = 0;out: spin_unlock_bh(&ipx_interfaces_lock); return ret;}static ipx_interface *ipxitf_auto_create(struct net_device *dev, unsigned short dlink_type){ 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 (htons(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 *arg){ struct ifreq ifr; int val; switch (cmd) { case SIOCSIFADDR: { struct sockaddr_ipx *sipx; ipx_interface_definition f; if (copy_from_user(&ifr, arg, sizeof(ifr))) return -EFAULT; sipx = (struct sockaddr_ipx *)&ifr.ifr_addr; if (sipx->sipx_family != AF_IPX) return -EINVAL; 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) return ipxitf_delete(&f); else return ipxitf_create(&f); } case SIOCGIFADDR: { int err = 0; struct sockaddr_ipx *sipx; ipx_interface *ipxif; struct net_device *dev; if (copy_from_user(&ifr, arg, sizeof(ifr))) return -EFAULT; sipx = (struct sockaddr_ipx *)&ifr.ifr_addr; dev = __dev_get_by_name(ifr.ifr_name); if (!dev) return -ENODEV; ipxif = ipxitf_find_using_phys(dev, ipx_map_frame_type(sipx->sipx_type)); if (!ipxif) return -EADDRNOTAVAIL; sipx->sipx_family = AF_IPX; sipx->sipx_network = ipxif->if_netnum; memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node)); if (copy_to_user(arg, &ifr, sizeof(ifr))) err = -EFAULT; ipxitf_put(ipxif); return err; } case SIOCAIPXITFCRT: if (get_user(val, (unsigned char *) arg)) return -EFAULT; ipxcfg_set_auto_create(val); break; case SIOCAIPXPRISLT: if (get_user(val, (unsigned char *) arg)) return -EFAULT; ipxcfg_set_auto_select(val); break; default: return -EINVAL; } return 0;}/* Routing tables for the IPX socket layer. */static inline void ipxrtr_hold(ipx_route *rt){ atomic_inc(&rt->refcnt);}static inline void ipxrtr_put(ipx_route *rt){ if (atomic_dec_and_test(&rt->refcnt)) kfree(rt);}static ipx_route *ipxrtr_lookup(__u32 net){ ipx_route *r; read_lock_bh(&ipx_routes_lock); for (r = ipx_routes; r && r->ir_net != net; r = r->ir_next) ; if (r) ipxrtr_hold(r); read_unlock_bh(&ipx_routes_lock); return r;}/* caller must hold a reference to intrfc */static int ipxrtr_add_route(__u32 network, ipx_interface *intrfc, unsigned char *node){ ipx_route *rt; int ret; /* Get a route structure; either existing or create */ rt = ipxrtr_lookup(network); if (!rt) { rt = kmalloc(sizeof(ipx_route), GFP_ATOMIC); ret = -EAGAIN; if (!rt) goto out; atomic_set(&rt->refcnt, 1); ipxrtr_hold(rt); write_lock_bh(&ipx_routes_lock); rt->ir_next = ipx_routes; ipx_routes = rt; write_unlock_bh(&ipx_routes_lock); } else { ret = -EEXIST; if (intrfc == ipx_internal_net) goto out_put; } rt->ir_net = network; rt->ir_intrfc = intrfc; if (!node) { memset(rt->ir_router_node, '\0', IPX_NODE_LEN); rt->ir_routed = 0; } else { memcpy(rt->ir_router_node, node, IPX_NODE_LEN); rt->ir_routed = 1; } ret = 0;out_put: ipxrtr_put(rt);out: return ret;}static void ipxrtr_del_routes(ipx_interface *intrfc){ ipx_route **r, *tmp; write_lock_bh(&ipx_routes_lock); for (r = &ipx_routes; (tmp = *r) != NULL;) { if (tmp->ir_intrfc == intrfc) { *r = tmp->ir_next; ipxrtr_put(tmp); } else r = &(tmp->ir_next); } write_unlock_bh(&ipx_routes_lock);}static int ipxrtr_create(ipx_route_definition *rd){ ipx_interface *intrfc; int ret = -ENETUNREACH; /* Find the appropriate interface */ intrfc = ipxitf_find_using_net(rd->ipx_router_network); if (!intrfc) goto out; ret = ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node); ipxitf_put(intrfc);out: return ret;}static int ipxrtr_delete(long net){ ipx_route **r; ipx_route *tmp; int err; write_lock_bh(&ipx_routes_lock); for (r = &ipx_routes; (tmp = *r) != NULL;) { if (tmp->ir_net == net) { /* Directly connected; can't lose route */ err = -EPERM; if (!tmp->ir_routed) goto out; *r = tmp->ir_next; ipxrtr_put(tmp); err = 0; goto out; } r = &(tmp->ir_next); } err = -ENOENT;out: write_unlock_bh(&ipx_routes_lock); return err;}/* * Checksum routine for IPX */ /* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize *//* This functions should *not* mess with packet contents */static __u16 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.) */ /* start at ipx_dest - We skip the checksum field and start with * ipx_type before the loop, not considering ipx_tctrl in the calc */ __u16 *p = (__u16 *)&packet->ipx_dest; __u32 i = (length >> 1) - 1; /* Number of complete words */ __u32 sum = packet->ipx_type << sizeof(packet->ipx_tctrl); /* Loop through all complete words except the checksum field, * ipx_type (accounted above) and ipx_tctrl (not used in the cksum) */ while (--i) sum += *p++; /* Add on the last part word if it exists */ if (packet->ipx_pktsize & __constant_htons(1)) sum += ntohs(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++; return ~sum;}/* * Route an outgoing frame from a socket. */static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, struct iovec *iov, int len, int noblock){ struct sk_buff *skb; ipx_interface *intrfc; struct ipxhdr *ipx; int size; int ipx_offset; ipx_route *rt = NULL; int err; /* Find the appropriate interface on which to send packet */ if (!usipx->sipx_network && ipx_primary_net) { usipx->sipx_network = ipx_primary_net->if_netnum; intrfc = ipx_primary_net; } else { rt = ipxrtr_lookup(usipx->sipx_network); err = -ENETUNREACH; if (!rt) goto out; intrfc = rt->ir_intrfc; } ipxitf_hold(intrfc); ipx_offset = intrfc->if_ipx_offset; size = sizeof(struct ipxhdr) + len + ipx_offset; skb = sock_alloc_send_skb(sk, size, noblock, &err); if (!skb) goto out_put; skb_reserve(skb, ipx_offset);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -