Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.24-rc5 294 lines 6.9 kB view raw
1/* 2 * Implements the IPX routing routines. 3 * Code moved from af_ipx.c. 4 * 5 * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2003 6 * 7 * See net/ipx/ChangeLog. 8 */ 9 10#include <linux/list.h> 11#include <linux/route.h> 12#include <linux/spinlock.h> 13 14#include <net/ipx.h> 15#include <net/sock.h> 16 17LIST_HEAD(ipx_routes); 18DEFINE_RWLOCK(ipx_routes_lock); 19 20extern struct ipx_interface *ipx_internal_net; 21 22extern __be16 ipx_cksum(struct ipxhdr *packet, int length); 23extern struct ipx_interface *ipxitf_find_using_net(__be32 net); 24extern int ipxitf_demux_socket(struct ipx_interface *intrfc, 25 struct sk_buff *skb, int copy); 26extern int ipxitf_demux_socket(struct ipx_interface *intrfc, 27 struct sk_buff *skb, int copy); 28extern int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, 29 char *node); 30extern struct ipx_interface *ipxitf_find_using_net(__be32 net); 31 32struct ipx_route *ipxrtr_lookup(__be32 net) 33{ 34 struct ipx_route *r; 35 36 read_lock_bh(&ipx_routes_lock); 37 list_for_each_entry(r, &ipx_routes, node) 38 if (r->ir_net == net) { 39 ipxrtr_hold(r); 40 goto unlock; 41 } 42 r = NULL; 43unlock: 44 read_unlock_bh(&ipx_routes_lock); 45 return r; 46} 47 48/* 49 * Caller must hold a reference to intrfc 50 */ 51int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc, 52 unsigned char *node) 53{ 54 struct ipx_route *rt; 55 int rc; 56 57 /* Get a route structure; either existing or create */ 58 rt = ipxrtr_lookup(network); 59 if (!rt) { 60 rt = kmalloc(sizeof(*rt), GFP_ATOMIC); 61 rc = -EAGAIN; 62 if (!rt) 63 goto out; 64 65 atomic_set(&rt->refcnt, 1); 66 ipxrtr_hold(rt); 67 write_lock_bh(&ipx_routes_lock); 68 list_add(&rt->node, &ipx_routes); 69 write_unlock_bh(&ipx_routes_lock); 70 } else { 71 rc = -EEXIST; 72 if (intrfc == ipx_internal_net) 73 goto out_put; 74 } 75 76 rt->ir_net = network; 77 rt->ir_intrfc = intrfc; 78 if (!node) { 79 memset(rt->ir_router_node, '\0', IPX_NODE_LEN); 80 rt->ir_routed = 0; 81 } else { 82 memcpy(rt->ir_router_node, node, IPX_NODE_LEN); 83 rt->ir_routed = 1; 84 } 85 86 rc = 0; 87out_put: 88 ipxrtr_put(rt); 89out: 90 return rc; 91} 92 93void ipxrtr_del_routes(struct ipx_interface *intrfc) 94{ 95 struct ipx_route *r, *tmp; 96 97 write_lock_bh(&ipx_routes_lock); 98 list_for_each_entry_safe(r, tmp, &ipx_routes, node) 99 if (r->ir_intrfc == intrfc) { 100 list_del(&r->node); 101 ipxrtr_put(r); 102 } 103 write_unlock_bh(&ipx_routes_lock); 104} 105 106static int ipxrtr_create(struct ipx_route_definition *rd) 107{ 108 struct ipx_interface *intrfc; 109 int rc = -ENETUNREACH; 110 111 /* Find the appropriate interface */ 112 intrfc = ipxitf_find_using_net(rd->ipx_router_network); 113 if (!intrfc) 114 goto out; 115 rc = ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node); 116 ipxitf_put(intrfc); 117out: 118 return rc; 119} 120 121static int ipxrtr_delete(__be32 net) 122{ 123 struct ipx_route *r, *tmp; 124 int rc; 125 126 write_lock_bh(&ipx_routes_lock); 127 list_for_each_entry_safe(r, tmp, &ipx_routes, node) 128 if (r->ir_net == net) { 129 /* Directly connected; can't lose route */ 130 rc = -EPERM; 131 if (!r->ir_routed) 132 goto out; 133 list_del(&r->node); 134 ipxrtr_put(r); 135 rc = 0; 136 goto out; 137 } 138 rc = -ENOENT; 139out: 140 write_unlock_bh(&ipx_routes_lock); 141 return rc; 142} 143 144/* 145 * The skb has to be unshared, we'll end up calling ipxitf_send, that'll 146 * modify the packet 147 */ 148int ipxrtr_route_skb(struct sk_buff *skb) 149{ 150 struct ipxhdr *ipx = ipx_hdr(skb); 151 struct ipx_route *r = ipxrtr_lookup(IPX_SKB_CB(skb)->ipx_dest_net); 152 153 if (!r) { /* no known route */ 154 kfree_skb(skb); 155 return 0; 156 } 157 158 ipxitf_hold(r->ir_intrfc); 159 ipxitf_send(r->ir_intrfc, skb, r->ir_routed ? 160 r->ir_router_node : ipx->ipx_dest.node); 161 ipxitf_put(r->ir_intrfc); 162 ipxrtr_put(r); 163 164 return 0; 165} 166 167/* 168 * Route an outgoing frame from a socket. 169 */ 170int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, 171 struct iovec *iov, size_t len, int noblock) 172{ 173 struct sk_buff *skb; 174 struct ipx_sock *ipxs = ipx_sk(sk); 175 struct ipx_interface *intrfc; 176 struct ipxhdr *ipx; 177 size_t size; 178 int ipx_offset; 179 struct ipx_route *rt = NULL; 180 int rc; 181 182 /* Find the appropriate interface on which to send packet */ 183 if (!usipx->sipx_network && ipx_primary_net) { 184 usipx->sipx_network = ipx_primary_net->if_netnum; 185 intrfc = ipx_primary_net; 186 } else { 187 rt = ipxrtr_lookup(usipx->sipx_network); 188 rc = -ENETUNREACH; 189 if (!rt) 190 goto out; 191 intrfc = rt->ir_intrfc; 192 } 193 194 ipxitf_hold(intrfc); 195 ipx_offset = intrfc->if_ipx_offset; 196 size = sizeof(struct ipxhdr) + len + ipx_offset; 197 198 skb = sock_alloc_send_skb(sk, size, noblock, &rc); 199 if (!skb) 200 goto out_put; 201 202 skb_reserve(skb, ipx_offset); 203 skb->sk = sk; 204 205 /* Fill in IPX header */ 206 skb_reset_network_header(skb); 207 skb_reset_transport_header(skb); 208 skb_put(skb, sizeof(struct ipxhdr)); 209 ipx = ipx_hdr(skb); 210 ipx->ipx_pktsize = htons(len + sizeof(struct ipxhdr)); 211 IPX_SKB_CB(skb)->ipx_tctrl = 0; 212 ipx->ipx_type = usipx->sipx_type; 213 214 IPX_SKB_CB(skb)->last_hop.index = -1; 215#ifdef CONFIG_IPX_INTERN 216 IPX_SKB_CB(skb)->ipx_source_net = ipxs->intrfc->if_netnum; 217 memcpy(ipx->ipx_source.node, ipxs->node, IPX_NODE_LEN); 218#else 219 rc = ntohs(ipxs->port); 220 if (rc == 0x453 || rc == 0x452) { 221 /* RIP/SAP special handling for mars_nwe */ 222 IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum; 223 memcpy(ipx->ipx_source.node, intrfc->if_node, IPX_NODE_LEN); 224 } else { 225 IPX_SKB_CB(skb)->ipx_source_net = ipxs->intrfc->if_netnum; 226 memcpy(ipx->ipx_source.node, ipxs->intrfc->if_node, 227 IPX_NODE_LEN); 228 } 229#endif /* CONFIG_IPX_INTERN */ 230 ipx->ipx_source.sock = ipxs->port; 231 IPX_SKB_CB(skb)->ipx_dest_net = usipx->sipx_network; 232 memcpy(ipx->ipx_dest.node, usipx->sipx_node, IPX_NODE_LEN); 233 ipx->ipx_dest.sock = usipx->sipx_port; 234 235 rc = memcpy_fromiovec(skb_put(skb, len), iov, len); 236 if (rc) { 237 kfree_skb(skb); 238 goto out_put; 239 } 240 241 /* Apply checksum. Not allowed on 802.3 links. */ 242 if (sk->sk_no_check || intrfc->if_dlink_type == htons(IPX_FRAME_8023)) 243 ipx->ipx_checksum = htons(0xFFFF); 244 else 245 ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr)); 246 247 rc = ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? 248 rt->ir_router_node : ipx->ipx_dest.node); 249out_put: 250 ipxitf_put(intrfc); 251 if (rt) 252 ipxrtr_put(rt); 253out: 254 return rc; 255} 256 257/* 258 * We use a normal struct rtentry for route handling 259 */ 260int ipxrtr_ioctl(unsigned int cmd, void __user *arg) 261{ 262 struct rtentry rt; /* Use these to behave like 'other' stacks */ 263 struct sockaddr_ipx *sg, *st; 264 int rc = -EFAULT; 265 266 if (copy_from_user(&rt, arg, sizeof(rt))) 267 goto out; 268 269 sg = (struct sockaddr_ipx *)&rt.rt_gateway; 270 st = (struct sockaddr_ipx *)&rt.rt_dst; 271 272 rc = -EINVAL; 273 if (!(rt.rt_flags & RTF_GATEWAY) || /* Direct routes are fixed */ 274 sg->sipx_family != AF_IPX || 275 st->sipx_family != AF_IPX) 276 goto out; 277 278 switch (cmd) { 279 case SIOCDELRT: 280 rc = ipxrtr_delete(st->sipx_network); 281 break; 282 case SIOCADDRT: { 283 struct ipx_route_definition f; 284 f.ipx_network = st->sipx_network; 285 f.ipx_router_network = sg->sipx_network; 286 memcpy(f.ipx_router_node, sg->sipx_node, IPX_NODE_LEN); 287 rc = ipxrtr_create(&f); 288 break; 289 } 290 } 291 292out: 293 return rc; 294}