diff options
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 12 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.h | 2 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe_netlink.c | 53 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.c | 106 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.h | 2 |
5 files changed, 165 insertions, 10 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 1ba53ea7..09bd8873 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -1419,6 +1419,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt) opt_dhcpv4 = conf_dhcpv4; } + if (opt_up) + ipoe_nl_add_interface(ifindex); + list_for_each_entry(serv, &serv_list, entry) { if (strcmp(ifname, serv->ifname)) continue; @@ -1576,6 +1579,8 @@ static void load_interfaces(struct conf_sect_t *sect) struct conf_option_t *opt; struct list_head *pos, *n; + ipoe_nl_delete_interfaces(); + list_for_each_entry(serv, &serv_list, entry) serv->active = 0; @@ -1629,7 +1634,12 @@ static void parse_local_net(const char *opt) if (mask == 32) mask = 0xffffffff; else - mask = (1 << mask) - 1; + mask = (1 << (32-mask)) - 1; + + addr = ntohl(addr); + mask = ~mask; + + //printf("%x/%x %x\n", htonl(addr), ~mask, htonl(addr)&(~mask)); ipoe_nl_add_net(addr & mask, mask); diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index 827cba31..bb5841e5 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -85,6 +85,8 @@ struct ipoe_serv *ipoe_find_serv(const char *ifname); void ipoe_nl_add_net(uint32_t addr, int mask); void ipoe_nl_delete_nets(void); +void ipoe_nl_add_interface(int ifindex); +void ipoe_nl_delete_interfaces(void); int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr); void ipoe_nl_delete(int ifindex); int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr); diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c index b92ec928..dde83a52 100644 --- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c +++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c @@ -82,6 +82,59 @@ void ipoe_nl_add_net(uint32_t addr, int mask) log_error("ipoe: nl_add_net: error talking to kernel\n"); } +void ipoe_nl_delete_interfaces(void) +{ + struct nlmsghdr *nlh; + struct genlmsghdr *ghdr; + struct { + struct nlmsghdr n; + char buf[1024]; + } req; + + if (rth.fd == -1) + return; + + nlh = &req.n; + nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_type = ipoe_genl_id; + + ghdr = NLMSG_DATA(&req.n); + ghdr->cmd = IPOE_CMD_DEL_IF; + + addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, -1); + + if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) + log_error("ipoe: nl_del_iface: error talking to kernel\n"); +} + +void ipoe_nl_add_interface(int ifindex) +{ + struct nlmsghdr *nlh; + struct genlmsghdr *ghdr; + struct { + struct nlmsghdr n; + char buf[1024]; + } req; + + if (rth.fd == -1) + return; + + nlh = &req.n; + nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_type = ipoe_genl_id; + + ghdr = NLMSG_DATA(&req.n); + ghdr->cmd = IPOE_CMD_ADD_IF; + + addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex); + + if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) + log_error("ipoe: nl_add_iface: error talking to kernel\n"); +} + + int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr) { struct rtnl_handle rth; diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index 54cb2176..bf86e8cd 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -49,16 +49,14 @@ #endif #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) -struct ipoe_stats -{ +struct ipoe_stats { struct u64_stats_sync sync; u64 packets; u64 bytes; }; #endif -struct ipoe_session -{ +struct ipoe_session { struct list_head entry; struct list_head entry2; @@ -78,8 +76,7 @@ struct ipoe_session #endif }; -struct ipoe_network -{ +struct ipoe_network { struct rcu_head rcu_head; struct list_head entry; @@ -87,8 +84,14 @@ struct ipoe_network __be32 mask; }; -struct ipoe_entry_u -{ +struct ipoe_iface { + struct rcu_head rcu_head; + struct list_head entry; + + int ifindex; +}; + +struct ipoe_entry_u { struct rcu_head rcu_head; struct list_head entry1; struct list_head entry2; @@ -103,6 +106,7 @@ static LIST_HEAD(ipoe_list2); static LIST_HEAD(ipoe_list2_u); static DEFINE_SEMAPHORE(ipoe_wlock); static LIST_HEAD(ipoe_networks); +static LIST_HEAD(ipoe_interfaces); static struct work_struct ipoe_queue_work; static struct sk_buff_head ipoe_queue; @@ -155,7 +159,26 @@ static int ipoe_check_network(__be32 addr) rcu_read_lock(); list_for_each_entry_rcu(n, &ipoe_networks, entry) { - if ((addr & n->mask) == n->addr) { + if ((ntohl(addr) & n->mask) == n->addr) { + r = 1; + break; + } + } + + rcu_read_unlock(); + + return r; +} + +static int ipoe_check_interface(int ifindex) +{ + struct ipoe_iface *i; + int r = 0; + + rcu_read_lock(); + + list_for_each_entry_rcu(i, &ipoe_interfaces, entry) { + if (i->ifindex == ifindex) { r = 1; break; } @@ -166,6 +189,7 @@ static int ipoe_check_network(__be32 addr) return r; } + static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer) { struct iphdr *iph; @@ -690,6 +714,8 @@ static unsigned int ipt_in_hook(unsigned int hook, struct sk_buff *skb, const st ses = ipoe_lookup(iph->saddr); if (!ses) { + if (!ipoe_check_interface(in->ifindex)) + return NF_ACCEPT; ipoe_queue_u(skb, iph->saddr); return NF_DROP; } @@ -1369,6 +1395,56 @@ static int ipoe_nl_cmd_del_net(struct sk_buff *skb, struct genl_info *info) return 0; } +static int ipoe_nl_cmd_add_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct ipoe_iface *i; + + if (!info->attrs[IPOE_ATTR_IFINDEX]) + return -EINVAL; + + i = kmalloc(sizeof(*i), GFP_KERNEL); + if (!i) + return -ENOMEM; + + i->ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); + + down(&ipoe_wlock); + list_add_tail_rcu(&i->entry, &ipoe_interfaces); + up(&ipoe_wlock); + + return 0; +} + +static int ipoe_nl_cmd_del_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct ipoe_iface *i; + int ifindex; + + if (!info->attrs[IPOE_ATTR_IFINDEX]) + return -EINVAL; + + ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]); + + rcu_read_lock(); + list_for_each_entry_rcu(i, &ipoe_interfaces, entry) { + if (ifindex == -1 || ifindex == i->ifindex) { + //pr_info("del net %08x/%08x\n", n->addr, n->mask); + list_del_rcu(&i->entry); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) + kfree_rcu(i, rcu_head); +#else + call_rcu(&i->rcu_head, __kfree_rcu); +#endif + } + } + rcu_read_unlock(); + + synchronize_rcu(); + + return 0; +} + + static struct nla_policy ipoe_nl_policy[IPOE_ATTR_MAX + 1] = { [IPOE_ATTR_NONE] = { .type = NLA_UNSPEC, }, @@ -1422,6 +1498,18 @@ static struct genl_ops ipoe_nl_ops[] = { .policy = ipoe_nl_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = IPOE_CMD_ADD_IF, + .doit = ipoe_nl_cmd_add_interface, + .policy = ipoe_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = IPOE_CMD_DEL_IF, + .doit = ipoe_nl_cmd_del_interface, + .policy = ipoe_nl_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_family ipoe_nl_family = { diff --git a/drivers/ipoe/ipoe.h b/drivers/ipoe/ipoe.h index d40ac21a..d0ac1e41 100644 --- a/drivers/ipoe/ipoe.h +++ b/drivers/ipoe/ipoe.h @@ -11,6 +11,8 @@ enum { IPOE_CMD_GET, IPOE_CMD_ADD_NET, IPOE_CMD_DEL_NET, + IPOE_CMD_ADD_IF, + IPOE_CMD_DEL_IF, IPOE_REP_PKT, __IPOE_CMD_MAX, }; |