diff options
author | Dmitry Kozlov <xeb@mail.ru> | 2016-03-18 23:15:20 +0300 |
---|---|---|
committer | Dmitry Kozlov <xeb@mail.ru> | 2016-03-18 23:15:20 +0300 |
commit | aa4ed7b9c637b70dc42a180b918fb4adb3e32d74 (patch) | |
tree | 4e8454f4c751db0619faa2e6333d6b90aa841158 | |
parent | 53eaf7555a5f3f0b60854acf7933484c98ada917 (diff) | |
download | accel-ppp-aa4ed7b9c637b70dc42a180b918fb4adb3e32d74.tar.gz accel-ppp-aa4ed7b9c637b70dc42a180b918fb4adb3e32d74.zip |
ipoe: implemented starting UP session by arp request
-rw-r--r-- | accel-pppd/ctrl/ipoe/arp.c | 12 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.c | 20 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe.h | 14 | ||||
-rw-r--r-- | accel-pppd/ctrl/ipoe/ipoe_netlink.c | 18 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.c | 92 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.h | 1 |
6 files changed, 109 insertions, 48 deletions
diff --git a/accel-pppd/ctrl/ipoe/arp.c b/accel-pppd/ctrl/ipoe/arp.c index 96996246..2bf5a951 100644 --- a/accel-pppd/ctrl/ipoe/arp.c +++ b/accel-pppd/ctrl/ipoe/arp.c @@ -26,18 +26,6 @@ #include "memdebug.h" -struct _arphdr { - __be16 ar_hrd; - __be16 ar_pro; - __u8 ar_hln; - __u8 ar_pln; - __be16 ar_op; - __u8 ar_sha[ETH_ALEN]; - __be32 ar_spa; - __u8 ar_tha[ETH_ALEN]; - __be32 ar_tpa; -} __packed; - struct arp_node { struct rb_node node; struct ipoe_serv *ipoe; diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 514e787a..e6f142a3 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -1748,15 +1748,16 @@ static void ipoe_recv_dhcpv4_relay(struct dhcpv4_packet *pack) } -static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struct ethhdr *eth, struct iphdr *iph) +static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struct ethhdr *eth, struct iphdr *iph, struct _arphdr *arph) { struct ipoe_session *ses; - uint8_t *hwaddr = eth->h_source; + uint8_t *hwaddr = arph ? arph->ar_sha : eth->h_source; + in_addr_t saddr = arph ? arph->ar_spa : iph->saddr; if (ap_shutdown) return NULL; - if (l4_redirect_list_check(iph->saddr)) + if (l4_redirect_list_check(saddr)) return NULL; ses = ipoe_session_alloc(); @@ -1764,8 +1765,8 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc return NULL; ses->serv = serv; - memcpy(ses->hwaddr, eth->h_source, 6); - ses->yiaddr = iph->saddr; + memcpy(ses->hwaddr, hwaddr, ETH_ALEN); + ses->yiaddr = saddr; ses->UP = 1; if (!serv->opt_shared) @@ -1779,7 +1780,7 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); } else { ses->ctrl.calling_station_id = _malloc(17); - u_inet_ntoa(iph->saddr, ses->ctrl.calling_station_id); + u_inet_ntoa(saddr, ses->ctrl.calling_station_id); } if (ses->serv->opt_username == USERNAME_IFNAME) @@ -1881,10 +1882,11 @@ struct ipoe_session *ipoe_session_alloc(void) return ses; } -void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph) +void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph, struct _arphdr *arph) { struct ipoe_serv *serv; struct ipoe_session *ses; + in_addr_t saddr = arph ? arph->ar_spa : iph->saddr; pthread_mutex_lock(&serv_lock); list_for_each_entry(serv, &serv_list, entry) { @@ -1904,14 +1906,14 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph) } list_for_each_entry(ses, &serv->sessions, entry) { - if (ses->yiaddr == iph->saddr) { + if (ses->yiaddr == saddr) { pthread_mutex_unlock(&serv->lock); pthread_mutex_unlock(&serv_lock); return; } } - ipoe_session_create_up(serv, eth, iph); + ipoe_session_create_up(serv, eth, iph, arph); pthread_mutex_unlock(&serv->lock); diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index 0cf14ead..52b3c8da 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -106,6 +106,18 @@ struct ipoe_session_info { uint32_t peer_addr; }; +struct _arphdr { + __be16 ar_hrd; + __be16 ar_pro; + __u8 ar_hln; + __u8 ar_pln; + __be16 ar_op; + __u8 ar_sha[ETH_ALEN]; + __be32 ar_spa; + __u8 ar_tha[ETH_ALEN]; + __be32 ar_tpa; +} __packed; + #ifdef USE_LUA char *ipoe_lua_get_username(struct ipoe_session *, const char *func); int ipoe_lua_make_vlan_name(const char *func, const char *parent, int svid, int cvid, char *name); @@ -114,7 +126,7 @@ int ipoe_lua_make_vlan_name(const char *func, const char *parent, int svid, int struct iphdr; struct ethhdr; -void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph); +void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph, struct _arphdr *arph); struct ipoe_session *ipoe_session_alloc(void); diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c index 9372a94c..8ed4d91f 100644 --- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c +++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c @@ -467,6 +467,7 @@ static void ipoe_up_handler(const struct sockaddr_nl *addr, struct nlmsghdr *h) int ifindex; struct iphdr *iph; struct ethhdr *eth; + struct _arphdr *arph; len -= NLMSG_LENGTH(GENL_HDRLEN); @@ -484,14 +485,23 @@ static void ipoe_up_handler(const struct sockaddr_nl *addr, struct nlmsghdr *h) parse_rtattr_nested(tb2, IPOE_ATTR_MAX, tb[i]); - if (!tb2[IPOE_ATTR_ETH_HDR] || !tb2[IPOE_ATTR_IP_HDR] || !tb2[IPOE_ATTR_IFINDEX]) + if (!tb2[IPOE_ATTR_IFINDEX]) continue; ifindex = *(uint32_t *)(RTA_DATA(tb2[IPOE_ATTR_IFINDEX])); - iph = (struct iphdr *)(RTA_DATA(tb2[IPOE_ATTR_IP_HDR])); - eth = (struct ethhdr *)(RTA_DATA(tb2[IPOE_ATTR_ETH_HDR])); - ipoe_recv_up(ifindex, eth, iph); + if (tb2[IPOE_ATTR_ARP_HDR]) { + arph = (struct _arphdr *)(RTA_DATA(tb2[IPOE_ATTR_ARP_HDR])); + iph = NULL; + eth = NULL; + } else if (tb2[IPOE_ATTR_ETH_HDR] && !tb2[IPOE_ATTR_IP_HDR]) { + iph = (struct iphdr *)(RTA_DATA(tb2[IPOE_ATTR_IP_HDR])); + eth = (struct ethhdr *)(RTA_DATA(tb2[IPOE_ATTR_ETH_HDR])); + arph = NULL; + } else + continue; + + ipoe_recv_up(ifindex, eth, iph, arph); } } diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index 7eccf6e1..d787f827 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -101,6 +101,24 @@ struct ipoe_entry_u { unsigned long tstamp; }; + +struct _arphdr { + __be16 ar_hrd; /* format of hardware address */ + __be16 ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + __be16 ar_op; /* ARP opcode (command) */ + + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + __be32 ar_sip; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + __be32 ar_tip; /* target IP address */ +} __packed; + + static struct list_head ipoe_list[HASH_BITS + 1]; static struct list_head ipoe_list1_u[HASH_BITS + 1]; static struct list_head ipoe_excl_list[HASH_BITS + 1]; @@ -504,25 +522,32 @@ static void ipoe_process_queue(struct work_struct *w) struct sk_buff *skb; struct ipoe_entry_u *e; struct ethhdr *eth; - struct iphdr *iph; + struct iphdr *iph = NULL; + struct _arphdr *arph = NULL; struct sk_buff *report_skb = NULL; void *header = NULL; struct nlattr *ns; int id = 1; + __be32 saddr; do { while ((skb = skb_dequeue(&ipoe_queue))) { - eth = eth_hdr(skb); - iph = ip_hdr(skb); + if (likely(skb->protocol == htons(ETH_P_IP))) { + iph = ip_hdr(skb); + saddr = iph->saddr; + } else { + arph = (struct _arphdr *)skb_network_header(skb); + saddr = arph->ar_sip; + } - e = ipoe_lookup2_u(iph->saddr); + e = ipoe_lookup2_u(saddr); if (!e) { e = kmalloc(sizeof(*e), GFP_KERNEL); - e->addr = iph->saddr; + e->addr = saddr; e->tstamp = jiffies; - list_add_tail_rcu(&e->entry1, &ipoe_list1_u[hash_addr(iph->saddr)]); + list_add_tail_rcu(&e->entry1, &ipoe_list1_u[hash_addr(saddr)]); list_add_tail(&e->entry2, &ipoe_list2_u); //pr_info("create %08x\n", e->addr); @@ -554,11 +579,17 @@ static void ipoe_process_queue(struct work_struct *w) if (nla_put_u32(report_skb, IPOE_ATTR_IFINDEX, skb->dev ? skb->dev->ifindex : skb->skb_iif)) goto nl_err; - if (nla_put(report_skb, IPOE_ATTR_ETH_HDR, sizeof(*eth), eth)) - goto nl_err; + if (likely(skb->protocol == htons(ETH_P_IP))) { + eth = eth_hdr(skb); + if (nla_put(report_skb, IPOE_ATTR_ETH_HDR, sizeof(*eth), eth)) + goto nl_err; - if (nla_put(report_skb, IPOE_ATTR_IP_HDR, sizeof(*iph), iph)) - goto nl_err; + if (nla_put(report_skb, IPOE_ATTR_IP_HDR, sizeof(*iph), iph)) + goto nl_err; + } else { + if (nla_put(report_skb, IPOE_ATTR_ARP_HDR, sizeof(*arph), arph)) + goto nl_err; + } if (nla_nest_end(report_skb, ns) >= IPOE_NLMSG_SIZE) { genlmsg_end(report_skb, header); @@ -671,10 +702,12 @@ static rx_handler_result_t ipoe_recv(struct sk_buff **pskb) struct ipoe_iface *i = rcu_dereference(dev->rx_handler_data); struct net_device *out = NULL; struct ipoe_session *ses = NULL; - struct iphdr *iph; + struct iphdr *iph = NULL; + struct _arphdr *arph = NULL; struct ethhdr *eth; int noff; struct net_device_stats *stats; + __be32 saddr; if (!i) return RX_HANDLER_PASS; @@ -682,21 +715,36 @@ static rx_handler_result_t ipoe_recv(struct sk_buff **pskb) if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) return RX_HANDLER_PASS; - if (skb->protocol != htons(ETH_P_IP)) - return RX_HANDLER_PASS; + if (likely(skb->protocol == htons(ETH_P_IP))) { + noff = skb_network_offset(skb); - noff = skb_network_offset(skb); + if (!pskb_may_pull(skb, sizeof(*iph) + noff)) + return RX_HANDLER_PASS; - if (!pskb_may_pull(skb, sizeof(*iph) + noff)) - return RX_HANDLER_PASS; + iph = ip_hdr(skb); + saddr = iph->saddr; - iph = ip_hdr(skb); + if (!saddr || saddr == 0xffffffff) + return RX_HANDLER_PASS; + } else if (likely(skb->protocol == htons(ETH_P_ARP))) { + noff = skb_network_offset(skb); + + if (skb->len != sizeof(*arph)) + return RX_HANDLER_PASS; + + if (!pskb_may_pull(skb, sizeof(*arph) + noff)) + return RX_HANDLER_PASS; + + arph = (struct _arphdr *)skb_network_header(skb); + if (arph->ar_op != htons(ARPOP_REQUEST)) + return RX_HANDLER_PASS; - if (!iph->saddr) + saddr = arph->ar_sip; + } else return RX_HANDLER_PASS; //pr_info("ipoe: recv %08x %08x\n", iph->saddr, iph->daddr); - ses = ipoe_lookup_rt(skb, iph->saddr, &out); + ses = ipoe_lookup_rt(skb, saddr, &out); if (!ses) { if (i->mode == 0) @@ -710,11 +758,11 @@ static rx_handler_result_t ipoe_recv(struct sk_buff **pskb) return RX_HANDLER_CONSUMED; } - if (ipoe_check_exclude(iph->saddr)) + if (ipoe_check_exclude(saddr)) return RX_HANDLER_PASS; - if (ipoe_check_network(iph->saddr)) { - if (ipoe_queue_u(skb, iph->saddr)) + if (ipoe_check_network(saddr)) { + if (ipoe_queue_u(skb, saddr)) kfree_skb(skb); } else return RX_HANDLER_PASS; diff --git a/drivers/ipoe/ipoe.h b/drivers/ipoe/ipoe.h index c735c2cf..4097e2da 100644 --- a/drivers/ipoe/ipoe.h +++ b/drivers/ipoe/ipoe.h @@ -33,6 +33,7 @@ enum { IPOE_ATTR_ETH_HDR, /* u32 */ IPOE_ATTR_IP_HDR, /* u32 */ IPOE_ATTR_MODE, /* u8 */ + IPOE_ATTR_ARP_HDR, /* u8 */ __IPOE_ATTR_MAX, }; |