summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c183
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h7
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe_netlink.c57
-rw-r--r--accel-pppd/ifcfg.c8
-rw-r--r--accel-pppd/session.c22
-rw-r--r--drivers/ipoe/ipoe.c180
6 files changed, 344 insertions, 113 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index eedd8cf..5878b0c 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -37,7 +37,13 @@
#define USERNAME_IFNAME 0
#define USERNAME_LUA 1
+#define MODE_L2 0
+#define MODE_L3 1
+
static int conf_dhcpv4 = 1;
+static int conf_up = 0;
+static int conf_mode = 0;
+static int conf_shared = 1;
//static int conf_dhcpv6;
static int conf_username;
@@ -51,7 +57,6 @@ static int conf_netmask = 24;
static int conf_lease_time = 600;
static int conf_lease_timeout = 660;
static int conf_verbose;
-static int conf_opt_single = 0;
static unsigned int stat_starting;
static unsigned int stat_active;
@@ -158,10 +163,10 @@ static void ipoe_session_start(struct ipoe_session *ses)
char *passwd;
struct ifreq ifr;
- if (ses->serv->opt_single)
+ if (ses->serv->opt_shared == 0)
strncpy(ses->ses.ifname, ses->serv->ifname, AP_IFNAME_LEN);
else {
- ses->ifindex = ipoe_nl_create(0, 0, ses->serv->ifname, ses->hwaddr);
+ ses->ifindex = ipoe_nl_create(0, 0, ses->dhcpv4_request ? ses->serv->ifname : NULL, ses->hwaddr);
if (ses->ifindex == -1) {
log_ppp_error("ipoe: failed to create interface\n");
ipoe_session_finished(&ses->ses);
@@ -178,6 +183,7 @@ static void ipoe_session_start(struct ipoe_session *ses)
}
strncpy(ses->ses.ifname, ifr.ifr_name, AP_IFNAME_LEN);
+ ses->ses.ifindex = ses->ifindex;
}
if (!ses->ses.username) {
@@ -236,6 +242,11 @@ static void ipoe_session_start(struct ipoe_session *ses)
ses->timer.expire = ipoe_session_timeout;
ses->timer.expire_tv.tv_sec = conf_offer_timeout;
triton_timer_add(&ses->ctx, &ses->timer, 0);
+ } else {
+ if (ipoe_nl_modify(ses->ifindex, ses->giaddr, ses->ses.ipv4->peer_addr, NULL, NULL))
+ ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 0);
+ else
+ ap_session_activate(&ses->ses);
}
}
@@ -493,7 +504,7 @@ static void ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *p
dhcpv4_print_packet(pack, log_ppp_info2);
}
- if (serv->opt_single)
+ if (serv->opt_shared == 0)
ipoe_drop_sessions(serv, ses);
if (ses->ses.state == AP_STATE_STARTING && !ses->dhcpv4_request) {
@@ -552,7 +563,9 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc
ses->ctrl.terminate = ipoe_session_terminate;
ses->ctrl.type = CTRL_TYPE_IPOE;
ses->ctrl.name = "ipoe";
-
+
+ ses->giaddr = iph->saddr;
+
ses->ctrl.calling_station_id = _malloc(17);
ses->ctrl.called_station_id = _malloc(17);
@@ -585,10 +598,13 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph)
list_for_each_entry(serv, &serv_list, entry) {
if (serv->ifindex != ifindex)
continue;
+
+ if (!serv->opt_up)
+ return;
pthread_mutex_lock(&serv->lock);
list_for_each_entry(ses, &serv->sessions, entry) {
- if (memcmp(ses->hwaddr, eth->h_source, 6) == 0) {
+ if (ses->giaddr == iph->saddr) {
pthread_mutex_unlock(&serv->lock);
return;
}
@@ -649,42 +665,105 @@ static void ipoe_drop_sessions(struct ipoe_serv *serv, struct ipoe_session *skip
static void add_interface(const char *ifname, int ifindex, const char *opt)
{
- int opt_single;
- const char *ptr;
+ char *str0, *str, *ptr1, *ptr2;
+ int end;
struct ipoe_serv *serv;
+ int opt_shared = conf_shared;
+ int opt_dhcpv4 = 0;
+ int opt_up = 0;
+ int opt_mode = conf_mode;
+
+ str0 = strchr(opt, ',');
+ if (str0) {
+ str0 = _strdup(str0 + 1);
+ str = str0;
+
+ while (1) {
+ for (ptr1 = str + 1; *ptr1 && *ptr1 != '='; ptr1++);
- ptr = strstr(opt, ",single");
- if (ptr) {
- if (ptr[7] && ptr[7] != ',')
- goto out_err_parse;
- opt_single = 1;
- } else {
- ptr = strstr(opt, ",shared");
- if (ptr) {
- if (ptr[7] && ptr[7] != ',')
- goto out_err_parse;
- opt_single = 0;
- } else
- opt_single = conf_opt_single;
+ if (!*ptr1)
+ goto parse_err;
+
+ *ptr1 = 0;
+
+ for (ptr2 = ++ptr1; *ptr2 && *ptr2 != ','; ptr2++);
+
+ end = *ptr2 == 0;
+
+ if (!end)
+ *ptr2 = 0;
+
+ if (ptr2 == ptr1)
+ goto parse_err;
+
+ if (strcmp(str, "start") == 0) {
+ if (!strcmp(ptr1, "up"))
+ opt_up = 1;
+ else if (!strcmp(ptr1, "dhcpv4"))
+ opt_dhcpv4 = 1;
+ else
+ goto parse_err;
+ } else if (strcmp(str, "shared") == 0) {
+ opt_shared = atoi(ptr1);
+ } else if (strcmp(str, "mode") == 0) {
+ if (!strcmp(ptr1, "L2"))
+ opt_mode = MODE_L2;
+ else if (!strcmp(ptr1, "L3"))
+ opt_mode = MODE_L3;
+ else
+ goto parse_err;
+ } else
+ goto parse_err;
+
+ if (end)
+ break;
+
+ str = ptr2 + 1;
+ }
+
+ _free(str0);
}
-
+
+ if (!opt_up && !opt_dhcpv4) {
+ opt_up = conf_up;
+ opt_dhcpv4 = conf_dhcpv4;
+ }
+
list_for_each_entry(serv, &serv_list, entry) {
- if (strcmp(ifname, serv->ifname) == 0) {
- serv->active = 1;
- serv->ifindex = ifindex;
- if (opt_single && !serv->opt_single)
- ipoe_drop_sessions(serv, NULL);
- serv->opt_single = opt_single;
- return;
+ if (!strcmp(ifname, serv->ifname))
+ continue;
+
+ serv->active = 1;
+ serv->ifindex = ifindex;
+
+ if ((opt_shared && !serv->opt_shared) || (!opt_shared && serv->opt_shared)) {
+ ipoe_drop_sessions(serv, NULL);
+ serv->opt_shared = opt_shared;
}
+
+ if (opt_dhcpv4 && !serv->dhcpv4) {
+ serv->dhcpv4 = dhcpv4_create(&serv->ctx, serv->ifname);
+ if (serv->dhcpv4)
+ serv->dhcpv4->recv = ipoe_recv_dhcpv4;
+ } else if (!opt_dhcpv4 && serv->dhcpv4) {
+ dhcpv4_free(serv->dhcpv4);
+ serv->dhcpv4 = NULL;
+ }
+
+ serv->opt_up = opt_up;
+ serv->opt_mode = conf_mode;
+
+ return;
}
serv = _malloc(sizeof(*serv));
memset(serv, 0, sizeof(*serv));
serv->ifname = _strdup(ifname);
serv->ifindex = ifindex;
- serv->opt_single = opt_single;
- serv->opt_dhcpv4 = conf_dhcpv4;
+ serv->opt_shared = opt_shared;
+ serv->opt_dhcpv4 = opt_dhcpv4;
+ serv->opt_up = opt_up;
+ serv->opt_mode = opt_mode;
serv->active = 1;
INIT_LIST_HEAD(&serv->sessions);
pthread_mutex_init(&serv->lock, NULL);
@@ -703,8 +782,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
return;
-out_err_parse:
+parse_err:
log_error("ipoe: failed to parse '%s'\n", opt);
+ _free(str0);
}
static void load_interface(const char *opt)
@@ -853,13 +933,11 @@ static void load_config(void)
{
const char *opt;
struct conf_sect_t *s = conf_get_section("ipoe");
+ struct conf_option_t *opt1;
if (!s)
return;
- load_interfaces(s);
- load_local_nets(s);
-
opt = conf_get_opt("ipoe", "username");
if (opt) {
if (strcmp(opt, "ifname") == 0)
@@ -901,6 +979,41 @@ static void load_config(void)
opt = conf_get_opt("ipoe", "lease-timeout");
if (opt)
conf_lease_timeout = atoi(opt);
+
+ opt = conf_get_opt("ipoe", "shared");
+ if (opt)
+ conf_shared = atoi(opt);
+ else
+ conf_shared = 1;
+
+ opt = conf_get_opt("ipoe", "mode");
+ if (opt) {
+ if (!strcmp(opt, "L2"))
+ conf_mode = MODE_L2;
+ else if (!strcmp(opt, "L3"))
+ conf_mode = MODE_L3;
+ else
+ log_emerg("ipoe: failed to parse 'mode=%s'\n", opt);
+ } else
+ conf_mode = MODE_L2;
+
+ conf_dhcpv4 = 0;
+ conf_up = 0;
+
+ list_for_each_entry(opt1, &s->items, entry) {
+ if (strcmp(opt1->name, "start"))
+ continue;
+ if (!strcmp(opt1->val, "dhcpv4"))
+ conf_dhcpv4 = 1;
+ else if (!strcmp(opt1->val, "up"))
+ conf_up = 1;
+ }
+
+ if (!conf_dhcpv4 && !conf_up)
+ conf_dhcpv4 = 1;
+
+ load_interfaces(s);
+ load_local_nets(s);
}
static void ipoe_init(void)
diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h
index 3076090..97b13e6 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.h
+++ b/accel-pppd/ctrl/ipoe/ipoe.h
@@ -15,11 +15,13 @@ struct ipoe_serv
char *ifname;
int ifindex;
int active;
- int opt_single;
- int opt_dhcpv4;
struct list_head sessions;
struct dhcpv4_serv *dhcpv4;
pthread_mutex_t lock;
+ int opt_mode;
+ int opt_shared:1;
+ int opt_dhcpv4:1;
+ int opt_up:1;
};
struct dhcp_opt
@@ -60,6 +62,7 @@ void ipoe_nl_add_net(uint32_t addr, int mask);
void ipoe_nl_delete_nets(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);
#endif
diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
index 57da0de..ec603d5 100644
--- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c
+++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
@@ -109,7 +109,7 @@ int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_
nlh->nlmsg_type = ipoe_genl_id;
ghdr = NLMSG_DATA(&req.n);
- ghdr->cmd = IPOE_CMD_DELETE;
+ ghdr->cmd = IPOE_CMD_CREATE;
if (peer_addr)
addattr32(nlh, 1024, IPOE_ATTR_PEER_ADDR, peer_addr);
@@ -163,6 +163,61 @@ out:
return ret;
}
+int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr)
+{
+ struct rtnl_handle rth;
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *ghdr;
+ int ret = 0;
+ struct {
+ struct nlmsghdr n;
+ char buf[1024];
+ } req;
+ union {
+ uint8_t hwaddr[6];
+ uint64_t u64;
+ } u;
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) {
+ log_ppp_error("ipoe: cannot open generic netlink socket\n");
+ return -1;
+ }
+
+ 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_MODIFY;
+
+ addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex);
+
+ if (peer_addr)
+ addattr32(nlh, 1024, IPOE_ATTR_PEER_ADDR, peer_addr);
+
+ if (addr)
+ addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr);
+
+ if (hwaddr) {
+ memcpy(u.hwaddr, hwaddr, 6);
+ addattr_l(nlh, 1024, IPOE_ATTR_HWADDR, &u.u64, 8);
+ }
+
+ if (ifname)
+ addattr_l(nlh, 1024, IPOE_ATTR_IFNAME, ifname, strlen(ifname) + 1);
+
+ if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) {
+ log_ppp_error("ipoe: nl_create: error talking to kernel\n");
+ ret = -1;
+ }
+
+ rtnl_close(&rth);
+
+ return ret;
+}
+
+
void ipoe_nl_delete(int ifindex)
{
struct rtnl_handle rth;
diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c
index 11251e1..134edfb 100644
--- a/accel-pppd/ifcfg.c
+++ b/accel-pppd/ifcfg.c
@@ -82,16 +82,16 @@ void ap_session_ifup(struct ap_session *ses)
if (ioctl(sock_fd, SIOCSIFADDR, &ifr))
log_ppp_error("failed to set IPv4 address: %s\n", strerror(errno));
- if (ses->ctrl->type == CTRL_TYPE_IPOE) {
+ /*if (ses->ctrl->type == CTRL_TYPE_IPOE) {
addr.sin_addr.s_addr = 0xffffffff;
memcpy(&ifr.ifr_netmask, &addr, sizeof(addr));
if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr))
log_ppp_error("failed to set IPv4 nask: %s\n", strerror(errno));
- }
+ }*/
addr.sin_addr.s_addr = ses->ipv4->peer_addr;
- if (ses->ctrl->type == CTRL_TYPE_IPOE) {
+ /*if (ses->ctrl->type == CTRL_TYPE_IPOE) {
memset(&rt, 0, sizeof(rt));
memcpy(&rt.rt_dst, &addr, sizeof(addr));
rt.rt_flags = RTF_HOST | RTF_UP;
@@ -99,7 +99,7 @@ void ap_session_ifup(struct ap_session *ses)
rt.rt_dev = ifr.ifr_name;
if (ioctl(sock_fd, SIOCADDRT, &rt, sizeof(rt)))
log_ppp_error("failed to add route: %s\n", strerror(errno));
- } else {
+ } else*/ {
memcpy(&ifr.ifr_dstaddr, &addr, sizeof(addr));
if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr))
diff --git a/accel-pppd/session.c b/accel-pppd/session.c
index 0064f54..886aa40 100644
--- a/accel-pppd/session.c
+++ b/accel-pppd/session.c
@@ -17,6 +17,7 @@
#include "log.h"
#include "events.h"
#include "ap_session.h"
+#include "spinlock.h"
#include "mempool.h"
#include "memdebug.h"
@@ -24,6 +25,10 @@ int conf_sid_ucase;
pthread_rwlock_t __export ses_lock = PTHREAD_RWLOCK_INITIALIZER;
__export LIST_HEAD(ses_list);
+#if __WORDSIZE == 32
+static spinlock_t seq_lock;
+#endif
+
int __export sock_fd;
int __export sock6_fd;
int __export urandom_fd;
@@ -39,6 +44,7 @@ void __export ap_session_init(struct ap_session *ses)
{
memset(ses, 0, sizeof(*ses));
INIT_LIST_HEAD(&ses->pd_list);
+ ses->ifindex = -1;
}
int __export ap_session_starting(struct ap_session *ses)
@@ -47,14 +53,16 @@ int __export ap_session_starting(struct ap_session *ses)
ses->start_time = time(NULL);
- memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, ses->ifname);
-
- if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
- log_ppp_error("ioctl(SIOCGIFINDEX): %s\n", strerror(errno));
- return -1;
+ if (ses->ifindex == -1) {
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, ses->ifname);
+
+ if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
+ log_ppp_error("ioctl(SIOCGIFINDEX): %s\n", strerror(errno));
+ return -1;
+ }
+ ses->ifindex = ifr.ifr_ifindex;
}
- ses->ifindex = ifr.ifr_ifindex;
generate_sessionid(ses);
diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c
index 1776a44..d9ba4f4 100644
--- a/drivers/ipoe/ipoe.c
+++ b/drivers/ipoe/ipoe.c
@@ -335,6 +335,7 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev)
struct net_device_stats *stats = &dev->stats;
struct iphdr *iph;
struct ethhdr *eth;
+ struct sk_buff *skb1;
/*struct arphdr *arp;
unsigned char *arp_ptr;
__be32 tip;*/
@@ -342,7 +343,7 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev)
if (!ses->peer_addr)
goto drop;
-
+
noff = skb_network_offset(skb);
if (skb->protocol == htons(ETH_P_IP)) {
@@ -361,6 +362,13 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
if (iph->daddr == ses->addr) {
+ if (skb_shared(skb)) {
+ skb1 = skb_clone(skb, GFP_ATOMIC);
+ if (!skb1)
+ goto drop;
+ skb = skb1;
+ }
+
if (ipoe_do_nat(skb, ses->peer_addr, 1))
goto drop;
@@ -406,12 +414,14 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
}*/
-
- skb->dev = ses->link_dev;
- //skb->skb_iif = dev->ifindex;
- dev_queue_xmit(skb);
+
+ if (ses->link_dev) {
+ skb->dev = ses->link_dev;
+ //skb->skb_iif = dev->ifindex;
+ dev_queue_xmit(skb);
- return NETDEV_TX_OK;
+ return NETDEV_TX_OK;
+ }
drop:
stats->tx_dropped++;
dev_kfree_skb(skb);
@@ -502,6 +512,7 @@ static int ipoe_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t
{
struct ipoe_session *ses = NULL;
struct iphdr *iph;
+ struct ethhdr *eth;
int noff;
struct sk_buff *skb1;
unsigned char *cb_ptr;
@@ -538,6 +549,12 @@ static int ipoe_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t
//pr_info("ipoe: recv cb=%x\n", *(__u16 *)cb_ptr);
+ if (ses->link_dev) {
+ eth = eth_hdr(skb);
+ if (memcmp(eth->h_source, ses->hwaddr, ETH_ALEN))
+ goto drop_unlock;
+ }
+
stats = &ses->dev->stats;
if (skb->dev == ses->dev) {
@@ -545,9 +562,11 @@ static int ipoe_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t
atomic_dec(&ses->refs);
goto drop;
}
-
- if (ses->addr && !ipoe_check_network(iph->daddr) && ipoe_do_nat(skb, ses->addr, 0))
- goto drop_unlock;
+
+ if (ses->addr && ipoe_check_network(iph->daddr)) {
+ atomic_dec(&ses->refs);
+ goto drop;
+ }
skb1 = skb_clone(skb, GFP_ATOMIC);
if (!skb1) {
@@ -555,8 +574,13 @@ static int ipoe_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t
goto drop_unlock;
}
+ if (ses->addr && ipoe_do_nat(skb1, ses->addr, 0)) {
+ kfree_skb(skb1);
+ goto drop_unlock;
+ }
+
skb1->dev = ses->dev;
- skb1->skb_iif = ses->dev->ifindex;
+ //skb1->skb_iif = ses->dev->ifindex;
cb_ptr = skb1->cb + sizeof(skb1->cb) - 2;
*(__u16 *)cb_ptr = IPOE_MAGIC;
@@ -619,7 +643,7 @@ static void ipoe_queue_u(struct sk_buff *skb, __u32 addr)
unsigned long ts;
if (ipoe_lookup1_u(addr, &ts) && jiffies_to_msecs(jiffies - ts) < IPOE_RATE_U) {
- pr_info("not queue %08x\n", addr);
+ //pr_info("not queue %08x\n", addr);
return;
}
@@ -630,7 +654,7 @@ static void ipoe_queue_u(struct sk_buff *skb, __u32 addr)
if (!skb)
return;
- pr_info("queue %08x\n", addr);
+ //pr_info("queue %08x\n", addr);
skb_queue_tail(&ipoe_queue, skb);
schedule_work(&ipoe_queue_work);
@@ -667,15 +691,15 @@ static void ipoe_process_queue(struct work_struct *w)
list_add_tail_rcu(&e->entry1, &ipoe_list1_u[hash_addr(iph->saddr)]);
list_add_tail(&e->entry2, &ipoe_list2_u);
- pr_info("create %08x\n", e->addr);
+ //pr_info("create %08x\n", e->addr);
} else if (jiffies_to_msecs(jiffies - e->tstamp) < IPOE_RATE_U) {
- pr_info("skip %08x\n", e->addr);
+ //pr_info("skip %08x\n", e->addr);
kfree_skb(skb);
continue;
} else {
e->tstamp = jiffies;
list_move_tail(&e->entry2, &ipoe_list2_u);
- pr_info("update %08x\n", e->addr);
+ //pr_info("update %08x\n", e->addr);
}
if (!report_skb) {
@@ -720,7 +744,7 @@ nl_err:
if (jiffies_to_msecs(jiffies - e->tstamp) < IPOE_TIMEOUT_U * 1000)
break;
- pr_info("free %08x\n", e->addr);
+ //pr_info("free %08x\n", e->addr);
list_del(&e->entry2);
list_del_rcu(&e->entry1);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)
@@ -754,8 +778,9 @@ static struct ipoe_session *ipoe_lookup(__be32 addr)
rcu_read_lock();
list_for_each_entry_rcu(ses, head, entry) {
- if (ses->addr == addr) {
+ if (ses->peer_addr == addr) {
atomic_inc(&ses->refs);
+ rcu_read_unlock();
return ses;
}
}
@@ -859,11 +884,11 @@ static void ipoe_netdev_setup(struct net_device *dev)
dev->type = ARPHRD_ETHER;
dev->hard_header_len = 0;
dev->mtu = ETH_DATA_LEN;
- dev->flags = 0;//IFF_NOARP | IFF_BROADCAST;
+ dev->flags = IFF_MULTICAST | IFF_POINTOPOINT;
dev->iflink = 0;
dev->addr_len = ETH_ALEN;
- dev->features = 0;//|= NETIF_F_NETNS_LOCAL;
- dev->header_ops = &ipoe_hard_header_ops,
+ dev->features |= NETIF_F_NETNS_LOCAL;
+ dev->header_ops = &ipoe_hard_header_ops,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
#endif
@@ -922,9 +947,9 @@ static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, c
}
if (addr)
- dev->flags = IFF_NOARP;
+ dev->flags |= IFF_NOARP;
else
- dev->flags = IFF_BROADCAST;
+ dev->flags &= ~IFF_NOARP;
rtnl_lock();
r = register_netdevice(dev);
@@ -991,23 +1016,19 @@ static int ipoe_nl_cmd_create(struct sk_buff *skb, struct genl_info *info)
int ret = 0;
char ifname[IFNAMSIZ];
__u8 hwaddr[ETH_ALEN];
+ struct ipoe_session *ses;
//struct net *net = genl_info_net(info);
- msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
- if (!msg) {
- ret = -ENOMEM;
- goto out;
- }
-
- hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
- &ipoe_nl_family, 0, IPOE_CMD_CREATE);
- if (IS_ERR(hdr)) {
- ret = PTR_ERR(hdr);
- goto err_out;
- }
-
- if (info->attrs[IPOE_ATTR_PEER_ADDR])
+ if (info->attrs[IPOE_ATTR_PEER_ADDR]) {
peer_addr = nla_get_be32(info->attrs[IPOE_ATTR_PEER_ADDR]);
+ if (peer_addr) {
+ ses = ipoe_lookup(peer_addr);
+ if (ses) {
+ atomic_dec(&ses->refs);
+ return -EEXIST;
+ }
+ }
+ }
if (info->attrs[IPOE_ATTR_ADDR])
addr = nla_get_be32(info->attrs[IPOE_ATTR_ADDR]);
@@ -1020,7 +1041,20 @@ static int ipoe_nl_cmd_create(struct sk_buff *skb, struct genl_info *info)
else
memset(hwaddr, 0, sizeof(hwaddr));
- pr_info("ipoe: create %08x %08x %s\n", peer_addr, addr, info->attrs[IPOE_ATTR_IFNAME] ? ifname : "-");
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+ &ipoe_nl_family, 0, IPOE_CMD_CREATE);
+ if (IS_ERR(hdr)) {
+ ret = PTR_ERR(hdr);
+ goto err_out;
+ }
+
+ //pr_info("ipoe: create %08x %08x %s\n", peer_addr, addr, info->attrs[IPOE_ATTR_IFNAME] ? ifname : "-");
ret = ipoe_create(peer_addr, addr, info->attrs[IPOE_ATTR_IFNAME] ? ifname : NULL, hwaddr);
@@ -1048,6 +1082,7 @@ out:
static int ipoe_nl_cmd_delete(struct sk_buff *skb, struct genl_info *info)
{
struct net_device *dev;
+ struct ipoe_session *ses;
int ifindex;
int r = 0;
int ret = -EINVAL;
@@ -1074,7 +1109,7 @@ static int ipoe_nl_cmd_delete(struct sk_buff *skb, struct genl_info *info)
ses = netdev_priv(dev);
- pr_info("ipoe: delete %08x\n", ses->peer_addr);
+ //pr_info("ipoe: delete %08x\n", ses->peer_addr);
if (ses->peer_addr)
list_del_rcu(&ses->entry);
@@ -1084,8 +1119,6 @@ static int ipoe_nl_cmd_delete(struct sk_buff *skb, struct genl_info *info)
synchronize_rcu();
- atomic_dec(&ses->refs);
-
while (atomic_read(&ses->refs))
schedule_timeout_uninterruptible(1);
@@ -1098,7 +1131,6 @@ static int ipoe_nl_cmd_delete(struct sk_buff *skb, struct genl_info *info)
out_unlock:
up(&ipoe_wlock);
-out:
return ret;
}
@@ -1107,15 +1139,16 @@ static int ipoe_nl_cmd_modify(struct sk_buff *skb, struct genl_info *info)
int ret = -EINVAL, r = 0;
char ifname[IFNAMSIZ];
struct net_device *dev, *link_dev, *old_dev;
- struct ipoe_session *ses;
+ struct ipoe_session *ses, *ses1;
int ifindex;
+ __be32 peer_addr;
if (!info->attrs[IPOE_ATTR_IFINDEX])
- goto out;
+ return -EINVAL;
down(&ipoe_wlock);
- ifindex = nla_get_be32(info->attrs[IPOE_ATTR_IFINDEX]);
+ ifindex = nla_get_u32(info->attrs[IPOE_ATTR_IFINDEX]);
rcu_read_lock();
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
@@ -1132,13 +1165,40 @@ static int ipoe_nl_cmd_modify(struct sk_buff *skb, struct genl_info *info)
ses = netdev_priv(dev);
+ if (info->attrs[IPOE_ATTR_PEER_ADDR]) {
+ peer_addr = nla_get_be32(info->attrs[IPOE_ATTR_PEER_ADDR]);
+ if (peer_addr) {
+ ses1 = ipoe_lookup(peer_addr);
+ if (ses1) {
+ atomic_dec(&ses1->refs);
+ if (ses1 != ses) {
+ ret = -EEXIST;
+ goto out_unlock;
+ }
+ }
+ }
+
+ if (ses->peer_addr) {
+ list_del_rcu(&ses->entry);
+ synchronize_rcu();
+ }
+
+ ses->peer_addr = peer_addr;
+
+ if (peer_addr)
+ list_add_tail_rcu(&ses->entry, &ipoe_list[hash_addr(peer_addr)]);
+ }
+
if (info->attrs[IPOE_ATTR_IFNAME]) {
nla_strlcpy(ifname, info->attrs[IPOE_ATTR_IFNAME], IFNAMSIZ - 1);
-
- link_dev = dev_get_by_name(&init_net, ifname);
+
+ if (*ifname) {
+ link_dev = dev_get_by_name(&init_net, ifname);
- if (!link_dev)
- goto out_unlock;
+ if (!link_dev)
+ goto out_unlock;
+ } else
+ link_dev = NULL;
old_dev = ses->link_dev;
ses->link_dev = link_dev;
@@ -1146,31 +1206,23 @@ static int ipoe_nl_cmd_modify(struct sk_buff *skb, struct genl_info *info)
dev_put(old_dev);
}
- if (info->attrs[IPOE_ATTR_PEER_ADDR]) {
- if (ses->peer_addr) {
- list_del_rcu(&ses->entry);
- synchronize_rcu();
- }
-
- ses->peer_addr = nla_get_be32(info->attrs[IPOE_ATTR_PEER_ADDR]);
-
- if (ses->peer_addr)
- list_add_tail_rcu(&ses->entry, &ipoe_list[hash_addr(ses->peer_addr)])
- }
-
- if (info->attrs[IPOE_ATTR_ADDR])
+ if (info->attrs[IPOE_ATTR_ADDR]) {
ses->addr = nla_get_be32(info->attrs[IPOE_ATTR_ADDR]);
+ if (ses->addr)
+ dev->flags |= IFF_NOARP;
+ else
+ dev->flags &= ~IFF_NOARP;
+ }
if (info->attrs[IPOE_ATTR_HWADDR])
nla_memcpy(ses->hwaddr, info->attrs[IPOE_ATTR_HWADDR], ETH_ALEN);
- pr_info("ipoe: modify %08x %08x\n", ses->peer_addr, ses->addr);
+ //pr_info("ipoe: modify %08x %08x\n", ses->peer_addr, ses->addr);
ret = 0;
out_unlock:
up(&ipoe_wlock);
-out:
return ret;
}
@@ -1400,7 +1452,7 @@ static void __exit ipoe_fini(void)
rcu_barrier();
while (!list_empty(&ipoe_list2)) {
- ses = list_entry(ipoe_list2.next, typeof(*ses), entry);
+ ses = list_entry(ipoe_list2.next, typeof(*ses), entry2);
list_del(&ses->entry2);
if (ses->link_dev)