📄 ddp.c
字号:
return atr ? atr->dev : NULL;}/* Set up a default router */static void atrtr_set_default(struct net_device *dev){ atrtr_default.dev = dev; atrtr_default.flags = RTF_UP; atrtr_default.gateway.s_net = htons(0); atrtr_default.gateway.s_node = 0;}/* * Add a router. Basically make sure it looks valid and stuff the * entry in the list. While it uses netranges we always set them to one * entry to work like netatalk. */static int atrtr_create(struct rtentry *r, struct net_device *devhint){ struct sockaddr_at *ta = (struct sockaddr_at *)&r->rt_dst; struct sockaddr_at *ga = (struct sockaddr_at *)&r->rt_gateway; struct atalk_route *rt; struct atalk_iface *iface, *riface; int retval = -EINVAL; /* * Fixme: Raise/Lower a routing change semaphore for these * operations. */ /* Validate the request */ if (ta->sat_family != AF_APPLETALK || (!devhint && ga->sat_family != AF_APPLETALK)) goto out; /* Now walk the routing table and make our decisions */ write_lock_bh(&atalk_routes_lock); for (rt = atalk_routes; rt; rt = rt->next) { if (r->rt_flags != rt->flags) continue; if (ta->sat_addr.s_net == rt->target.s_net) { if (!(rt->flags & RTF_HOST)) break; if (ta->sat_addr.s_node == rt->target.s_node) break; } } if (!devhint) { riface = NULL; read_lock_bh(&atalk_interfaces_lock); for (iface = atalk_interfaces; iface; iface = iface->next) { if (!riface && ntohs(ga->sat_addr.s_net) >= ntohs(iface->nets.nr_firstnet) && ntohs(ga->sat_addr.s_net) <= ntohs(iface->nets.nr_lastnet)) riface = iface; if (ga->sat_addr.s_net == iface->address.s_net && ga->sat_addr.s_node == iface->address.s_node) riface = iface; } read_unlock_bh(&atalk_interfaces_lock); retval = -ENETUNREACH; if (!riface) goto out_unlock; devhint = riface->dev; } if (!rt) { rt = kzalloc(sizeof(*rt), GFP_ATOMIC); retval = -ENOBUFS; if (!rt) goto out_unlock; rt->next = atalk_routes; atalk_routes = rt; } /* Fill in the routing entry */ rt->target = ta->sat_addr; dev_hold(devhint); rt->dev = devhint; rt->flags = r->rt_flags; rt->gateway = ga->sat_addr; retval = 0;out_unlock: write_unlock_bh(&atalk_routes_lock);out: return retval;}/* Delete a route. Find it and discard it */static int atrtr_delete(struct atalk_addr * addr){ struct atalk_route **r = &atalk_routes; int retval = 0; struct atalk_route *tmp; write_lock_bh(&atalk_routes_lock); while ((tmp = *r) != NULL) { if (tmp->target.s_net == addr->s_net && (!(tmp->flags&RTF_GATEWAY) || tmp->target.s_node == addr->s_node)) { *r = tmp->next; dev_put(tmp->dev); kfree(tmp); goto out; } r = &tmp->next; } retval = -ENOENT;out: write_unlock_bh(&atalk_routes_lock); return retval;}/* * Called when a device is downed. Just throw away any routes * via it. */static void atrtr_device_down(struct net_device *dev){ struct atalk_route **r = &atalk_routes; struct atalk_route *tmp; write_lock_bh(&atalk_routes_lock); while ((tmp = *r) != NULL) { if (tmp->dev == dev) { *r = tmp->next; dev_put(dev); kfree(tmp); } else r = &tmp->next; } write_unlock_bh(&atalk_routes_lock); if (atrtr_default.dev == dev) atrtr_set_default(NULL);}/* Actually down the interface */static inline void atalk_dev_down(struct net_device *dev){ atrtr_device_down(dev); /* Remove all routes for the device */ aarp_device_down(dev); /* Remove AARP entries for the device */ atif_drop_device(dev); /* Remove the device */}/* * A device event has occurred. Watch for devices going down and * delete our use of them (iface and route). */static int ddp_device_event(struct notifier_block *this, unsigned long event, void *ptr){ struct net_device *dev = ptr; if (dev->nd_net != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) /* Discard any use of this */ atalk_dev_down(dev); return NOTIFY_DONE;}/* ioctl calls. Shouldn't even need touching *//* Device configuration ioctl calls */static int atif_ioctl(int cmd, void __user *arg){ static char aarp_mcast[6] = { 0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF }; struct ifreq atreq; struct atalk_netrange *nr; struct sockaddr_at *sa; struct net_device *dev; struct atalk_iface *atif; int ct; int limit; struct rtentry rtdef; int add_route; if (copy_from_user(&atreq, arg, sizeof(atreq))) return -EFAULT; dev = __dev_get_by_name(&init_net, atreq.ifr_name); if (!dev) return -ENODEV; sa = (struct sockaddr_at *)&atreq.ifr_addr; atif = atalk_find_dev(dev); switch (cmd) { case SIOCSIFADDR: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (sa->sat_family != AF_APPLETALK) return -EINVAL; if (dev->type != ARPHRD_ETHER && dev->type != ARPHRD_LOOPBACK && dev->type != ARPHRD_LOCALTLK && dev->type != ARPHRD_PPP) return -EPROTONOSUPPORT; nr = (struct atalk_netrange *)&sa->sat_zero[0]; add_route = 1; /* * if this is a point-to-point iface, and we already * have an iface for this AppleTalk address, then we * should not add a route */ if ((dev->flags & IFF_POINTOPOINT) && atalk_find_interface(sa->sat_addr.s_net, sa->sat_addr.s_node)) { printk(KERN_DEBUG "AppleTalk: point-to-point " "interface added with " "existing address\n"); add_route = 0; } /* * Phase 1 is fine on LocalTalk but we don't do * EtherTalk phase 1. Anyone wanting to add it go ahead. */ if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2) return -EPROTONOSUPPORT; if (sa->sat_addr.s_node == ATADDR_BCAST || sa->sat_addr.s_node == 254) return -EINVAL; if (atif) { /* Already setting address */ if (atif->status & ATIF_PROBE) return -EBUSY; atif->address.s_net = sa->sat_addr.s_net; atif->address.s_node = sa->sat_addr.s_node; atrtr_device_down(dev); /* Flush old routes */ } else { atif = atif_add_device(dev, &sa->sat_addr); if (!atif) return -ENOMEM; } atif->nets = *nr; /* * Check if the chosen address is used. If so we * error and atalkd will try another. */ if (!(dev->flags & IFF_LOOPBACK) && !(dev->flags & IFF_POINTOPOINT) && atif_probe_device(atif) < 0) { atif_drop_device(dev); return -EADDRINUSE; } /* Hey it worked - add the direct routes */ sa = (struct sockaddr_at *)&rtdef.rt_gateway; sa->sat_family = AF_APPLETALK; sa->sat_addr.s_net = atif->address.s_net; sa->sat_addr.s_node = atif->address.s_node; sa = (struct sockaddr_at *)&rtdef.rt_dst; rtdef.rt_flags = RTF_UP; sa->sat_family = AF_APPLETALK; sa->sat_addr.s_node = ATADDR_ANYNODE; if (dev->flags & IFF_LOOPBACK || dev->flags & IFF_POINTOPOINT) rtdef.rt_flags |= RTF_HOST; /* Routerless initial state */ if (nr->nr_firstnet == htons(0) && nr->nr_lastnet == htons(0xFFFE)) { sa->sat_addr.s_net = atif->address.s_net; atrtr_create(&rtdef, dev); atrtr_set_default(dev); } else { limit = ntohs(nr->nr_lastnet); if (limit - ntohs(nr->nr_firstnet) > 4096) { printk(KERN_WARNING "Too many routes/" "iface.\n"); return -EINVAL; } if (add_route) for (ct = ntohs(nr->nr_firstnet); ct <= limit; ct++) { sa->sat_addr.s_net = htons(ct); atrtr_create(&rtdef, dev); } } dev_mc_add(dev, aarp_mcast, 6, 1); return 0; case SIOCGIFADDR: if (!atif) return -EADDRNOTAVAIL; sa->sat_family = AF_APPLETALK; sa->sat_addr = atif->address; break; case SIOCGIFBRDADDR: if (!atif) return -EADDRNOTAVAIL; sa->sat_family = AF_APPLETALK; sa->sat_addr.s_net = atif->address.s_net; sa->sat_addr.s_node = ATADDR_BCAST; break; case SIOCATALKDIFADDR: case SIOCDIFADDR: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (sa->sat_family != AF_APPLETALK) return -EINVAL; atalk_dev_down(dev); break; case SIOCSARP: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (sa->sat_family != AF_APPLETALK) return -EINVAL; if (!atif) return -EADDRNOTAVAIL; /* * for now, we only support proxy AARP on ELAP; * we should be able to do it for LocalTalk, too. */ if (dev->type != ARPHRD_ETHER) return -EPROTONOSUPPORT; /* * atif points to the current interface on this network; * we aren't concerned about its current status (at * least for now), but it has all the settings about * the network we're going to probe. Consequently, it * must exist. */ if (!atif) return -EADDRNOTAVAIL; nr = (struct atalk_netrange *)&(atif->nets); /* * Phase 1 is fine on Localtalk but we don't do * Ethertalk phase 1. Anyone wanting to add it go ahead. */ if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2) return -EPROTONOSUPPORT; if (sa->sat_addr.s_node == ATADDR_BCAST || sa->sat_addr.s_node == 254) return -EINVAL; /* * Check if the chosen address is used. If so we * error and ATCP will try another. */ if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0) return -EADDRINUSE; /* * We now have an address on the local network, and * the AARP code will defend it for us until we take it * down. We don't set up any routes right now, because * ATCP will install them manually via SIOCADDRT. */ break; case SIOCDARP: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (sa->sat_family != AF_APPLETALK) return -EINVAL; if (!atif) return -EADDRNOTAVAIL; /* give to aarp module to remove proxy entry */ aarp_proxy_remove(atif->dev, &(sa->sat_addr)); return 0; } return copy_to_user(arg, &atreq, sizeof(atreq)) ? -EFAULT : 0;}/* Routing ioctl() calls */static int atrtr_ioctl(unsigned int cmd, void __user *arg){ struct rtentry rt; if (copy_from_user(&rt, arg, sizeof(rt))) return -EFAULT; switch (cmd) { case SIOCDELRT: if (rt.rt_dst.sa_family != AF_APPLETALK) return -EINVAL; return atrtr_delete(&((struct sockaddr_at *) &rt.rt_dst)->sat_addr); case SIOCADDRT: { struct net_device *dev = NULL; if (rt.rt_dev) { char name[IFNAMSIZ]; if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1)) return -EFAULT; name[IFNAMSIZ-1] = '\0'; dev = __dev_get_by_name(&init_net, name); if (!dev) return -ENODEV; } return atrtr_create(&rt, dev); } } return -EINVAL;}/**************************************************************************\* ** Handling for system calls applied via the various interfaces to an ** AppleTalk socket object. ** *\**************************************************************************//* * Checksum: This is 'optional'. It's quite likely also a good * candidate for assembler hackery 8) */static unsigned long atalk_sum_partial(const unsigned char *data, int len, unsigned long sum){ /* This ought to be unwrapped neatly. I'll trust gcc for now */ while (len--) { sum += *data; sum <<= 1; if (sum & 0x10000) { sum++; sum &= 0xffff; } data++; } return sum;}/* Checksum skb data -- similar to skb_checksum */static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset, int len, unsigned long sum){ int start = skb_headlen(skb); int i, copy; /* checksum stuff in header space */ if ( (copy = start - offset) > 0) { if (copy > len) copy = len; sum = atalk_sum_partial(skb->data + offset, copy, sum); if ( (len -= copy) == 0) return sum; offset += copy; } /* checksum stuff in frags */ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { int end; BUG_TRAP(start <= offset + len); end = start + skb_shinfo(skb)->frags[i].size; if ((copy = end - offset) > 0) { u8 *vaddr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; if (copy > len) copy = len; vaddr = kmap_skb_frag(frag);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -