Commit e442c99d authored by David S. Miller's avatar David S. Miller

[IPV4/IPV6]: Cleanup inet{,6}_protocol.

parent 8f6174bf
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <linux/ipv6.h> #include <linux/ipv6.h>
#endif #endif
#define MAX_INET_PROTOS 32 /* Must be a power of 2 */ #define MAX_INET_PROTOS 256 /* Must be a power of 2 */
/* This is used to register protocols. */ /* This is used to register protocols. */
...@@ -38,11 +38,6 @@ struct inet_protocol ...@@ -38,11 +38,6 @@ struct inet_protocol
{ {
int (*handler)(struct sk_buff *skb); int (*handler)(struct sk_buff *skb);
void (*err_handler)(struct sk_buff *skb, u32 info); void (*err_handler)(struct sk_buff *skb, u32 info);
struct inet_protocol *next;
unsigned char protocol;
unsigned char copy:1;
void *data;
const char *name;
}; };
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
...@@ -54,11 +49,6 @@ struct inet6_protocol ...@@ -54,11 +49,6 @@ struct inet6_protocol
struct inet6_skb_parm *opt, struct inet6_skb_parm *opt,
int type, int code, int offset, int type, int code, int offset,
__u32 info); __u32 info);
struct inet6_protocol *next;
unsigned char protocol;
unsigned char copy:1;
void *data;
const char *name;
}; };
#endif #endif
...@@ -93,14 +83,14 @@ extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; ...@@ -93,14 +83,14 @@ extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
extern struct list_head inetsw6[SOCK_MAX]; extern struct list_head inetsw6[SOCK_MAX];
#endif #endif
extern void inet_add_protocol(struct inet_protocol *prot); extern int inet_add_protocol(struct inet_protocol *prot, unsigned char num);
extern int inet_del_protocol(struct inet_protocol *prot); extern int inet_del_protocol(struct inet_protocol *prot, unsigned char num);
extern void inet_register_protosw(struct inet_protosw *p); extern void inet_register_protosw(struct inet_protosw *p);
extern void inet_unregister_protosw(struct inet_protosw *p); extern void inet_unregister_protosw(struct inet_protosw *p);
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
extern void inet6_add_protocol(struct inet6_protocol *prot); extern int inet6_add_protocol(struct inet6_protocol *prot, unsigned char num);
extern int inet6_del_protocol(struct inet6_protocol *prot); extern int inet6_del_protocol(struct inet6_protocol *prot, unsigned char num);
extern void inet6_register_protosw(struct inet_protosw *p); extern void inet6_register_protosw(struct inet_protosw *p);
extern void inet6_unregister_protosw(struct inet_protosw *p); extern void inet6_unregister_protosw(struct inet_protosw *p);
#endif #endif
......
...@@ -37,6 +37,6 @@ extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, ...@@ -37,6 +37,6 @@ extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
unsigned long raddr, unsigned long laddr, unsigned long raddr, unsigned long laddr,
int dif); int dif);
extern struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash); extern void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
#endif /* _RAW_H */ #endif /* _RAW_H */
...@@ -7,9 +7,7 @@ ...@@ -7,9 +7,7 @@
extern struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE]; extern struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
extern rwlock_t raw_v6_lock; extern rwlock_t raw_v6_lock;
extern struct sock * ipv6_raw_deliver(struct sk_buff *skb, extern void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
int nexthdr);
extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
struct in6_addr *loc_addr, struct in6_addr *rmt_addr); struct in6_addr *loc_addr, struct in6_addr *rmt_addr);
......
...@@ -1093,6 +1093,25 @@ void inet_unregister_protosw(struct inet_protosw *p) ...@@ -1093,6 +1093,25 @@ void inet_unregister_protosw(struct inet_protosw *p)
} }
} }
#ifdef CONFIG_IP_MULTICAST
static struct inet_protocol igmp_protocol = {
.handler = igmp_rcv,
};
#endif
static struct inet_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
};
static struct inet_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
};
static struct inet_protocol icmp_protocol = {
.handler = icmp_rcv,
};
/* /*
* Called by socket.c on kernel startup. * Called by socket.c on kernel startup.
...@@ -1101,7 +1120,6 @@ void inet_unregister_protosw(struct inet_protosw *p) ...@@ -1101,7 +1120,6 @@ void inet_unregister_protosw(struct inet_protosw *p)
static int __init inet_init(void) static int __init inet_init(void)
{ {
struct sk_buff *dummy_skb; struct sk_buff *dummy_skb;
struct inet_protocol *p;
struct inet_protosw *q; struct inet_protosw *q;
struct list_head *r; struct list_head *r;
...@@ -1131,16 +1149,19 @@ static int __init inet_init(void) ...@@ -1131,16 +1149,19 @@ static int __init inet_init(void)
(void)sock_register(&inet_family_ops); (void)sock_register(&inet_family_ops);
/* /*
* Add all the protocols. * Add all the base protocols.
*/ */
printk(KERN_INFO "IP Protocols: "); if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
for (p = inet_protocol_base; p;) { printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
struct inet_protocol *tmp = (struct inet_protocol *)p->next; if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
inet_add_protocol(p); printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
printk("%s%s", p->name, tmp ? ", " : "\n"); if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
p = tmp; printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
} #ifdef CONFIG_IP_MULTICAST
if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
#endif
/* Register the socket-side information for inet_create. */ /* Register the socket-side information for inet_create. */
for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r) for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
......
...@@ -719,23 +719,10 @@ static void icmp_unreach(struct sk_buff *skb) ...@@ -719,23 +719,10 @@ static void icmp_unreach(struct sk_buff *skb)
* we are OK. * we are OK.
*/ */
ipprot = (struct inet_protocol *)inet_protos[hash]; ipprot = inet_protos[hash];
while (ipprot) { if (ipprot && ipprot->err_handler)
struct inet_protocol *nextip; ipprot->err_handler(skb, info);
nextip = (struct inet_protocol *)ipprot->next;
/*
* Pass it off to everyone who wants it.
*/
/* RFC1122: OK. Passes appropriate ICMP errors to the */
/* appropriate protocol layer (MUST), as per 3.2.2. */
if (protocol == ipprot->protocol && ipprot->err_handler)
ipprot->err_handler(skb, info);
ipprot = nextip;
}
out: out:
return; return;
out_err: out_err:
......
...@@ -1259,13 +1259,8 @@ int __init ipgre_fb_tunnel_init(struct net_device *dev) ...@@ -1259,13 +1259,8 @@ int __init ipgre_fb_tunnel_init(struct net_device *dev)
static struct inet_protocol ipgre_protocol = { static struct inet_protocol ipgre_protocol = {
ipgre_rcv, /* GRE handler */ .handler = ipgre_rcv,
ipgre_err, /* TUNNEL error control */ .err_handler = ipgre_err,
0, /* next */
IPPROTO_GRE, /* protocol ID */
0, /* copy */
NULL, /* data */
"GRE" /* name */
}; };
...@@ -1281,9 +1276,13 @@ int __init ipgre_init(void) ...@@ -1281,9 +1276,13 @@ int __init ipgre_init(void)
{ {
printk(KERN_INFO "GRE over IPv4 tunneling driver\n"); printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
if (inet_add_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) {
printk(KERN_INFO "ipgre init: can't add protocol\n");
return -EAGAIN;
}
ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel; ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel;
register_netdev(&ipgre_fb_tunnel_dev); register_netdev(&ipgre_fb_tunnel_dev);
inet_add_protocol(&ipgre_protocol);
return 0; return 0;
} }
...@@ -1291,7 +1290,7 @@ int __init ipgre_init(void) ...@@ -1291,7 +1290,7 @@ int __init ipgre_init(void)
void cleanup_module(void) void cleanup_module(void)
{ {
if ( inet_del_protocol(&ipgre_protocol) < 0 ) if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
printk(KERN_INFO "ipgre close: can't remove protocol\n"); printk(KERN_INFO "ipgre close: can't remove protocol\n");
unregister_netdev(&ipgre_fb_tunnel_dev); unregister_netdev(&ipgre_fb_tunnel_dev);
......
...@@ -194,28 +194,6 @@ int ip_call_ra_chain(struct sk_buff *skb) ...@@ -194,28 +194,6 @@ int ip_call_ra_chain(struct sk_buff *skb)
return 0; return 0;
} }
/* Handle this out of line, it is rare. */
static int ip_run_ipprot(struct sk_buff *skb, struct iphdr *iph,
struct inet_protocol *ipprot, int force_copy)
{
int ret = 0;
do {
if (ipprot->protocol == iph->protocol) {
struct sk_buff *skb2 = skb;
if (ipprot->copy || force_copy)
skb2 = skb_clone(skb, GFP_ATOMIC);
if(skb2 != NULL) {
ret = 1;
ipprot->handler(skb2);
}
}
ipprot = (struct inet_protocol *) ipprot->next;
} while(ipprot != NULL);
return ret;
}
static inline int ip_local_deliver_finish(struct sk_buff *skb) static inline int ip_local_deliver_finish(struct sk_buff *skb)
{ {
int ihl = skb->nh.iph->ihl*4; int ihl = skb->nh.iph->ihl*4;
...@@ -239,44 +217,31 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb) ...@@ -239,44 +217,31 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
{ {
/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
int protocol = skb->nh.iph->protocol; int protocol = skb->nh.iph->protocol;
int hash = protocol & (MAX_INET_PROTOS - 1); int hash;
struct sock *raw_sk = raw_v4_htable[hash]; struct sock *raw_sk;
struct inet_protocol *ipprot; struct inet_protocol *ipprot;
int flag;
resubmit:
hash = protocol & (MAX_INET_PROTOS - 1);
raw_sk = raw_v4_htable[hash];
/* If there maybe a raw socket we must check - if not we /* If there maybe a raw socket we must check - if not we
* don't care less * don't care less
*/ */
if(raw_sk != NULL) if (raw_sk)
raw_sk = raw_v4_input(skb, skb->nh.iph, hash); raw_v4_input(skb, skb->nh.iph, hash);
ipprot = (struct inet_protocol *) inet_protos[hash]; if ((ipprot = inet_protos[hash]) != NULL) {
flag = 0; int ret = ipprot->handler(skb);
if(ipprot != NULL) { if (ret < 0) {
if(raw_sk == NULL && protocol = -ret;
ipprot->next == NULL && goto resubmit;
ipprot->protocol == protocol) { }
int ret; } else {
if (!raw_sk) {
/* Fast path... */ icmp_send(skb, ICMP_DEST_UNREACH,
ret = ipprot->handler(skb); ICMP_PROT_UNREACH, 0);
return ret;
} else {
flag = ip_run_ipprot(skb, skb->nh.iph, ipprot, (raw_sk != NULL));
} }
}
/* All protocols checked.
* If this packet was a broadcast, we may *not* reply to it, since that
* causes (proven, grin) ARP storms and a leakage of memory (i.e. all
* ICMP reply messages get queued up for transmission...)
*/
if(raw_sk != NULL) { /* Shift to last raw user */
raw_rcv(raw_sk, skb);
sock_put(raw_sk);
} else if (!flag) { /* Free and report errors */
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
kfree_skb(skb); kfree_skb(skb);
} }
} }
......
...@@ -877,10 +877,8 @@ int __init ipip_fb_tunnel_init(struct net_device *dev) ...@@ -877,10 +877,8 @@ int __init ipip_fb_tunnel_init(struct net_device *dev)
} }
static struct inet_protocol ipip_protocol = { static struct inet_protocol ipip_protocol = {
.handler = ipip_rcv, .handler = ipip_rcv,
.err_handler = ipip_err, .err_handler = ipip_err,
.protocol = IPPROTO_IPIP,
.name = "IPIP"
}; };
static char banner[] __initdata = static char banner[] __initdata =
...@@ -890,15 +888,19 @@ int __init ipip_init(void) ...@@ -890,15 +888,19 @@ int __init ipip_init(void)
{ {
printk(banner); printk(banner);
if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) {
printk(KERN_INFO "ipip init: can't add protocol\n");
return -EAGAIN;
}
ipip_fb_tunnel_dev.priv = (void*)&ipip_fb_tunnel; ipip_fb_tunnel_dev.priv = (void*)&ipip_fb_tunnel;
register_netdev(&ipip_fb_tunnel_dev); register_netdev(&ipip_fb_tunnel_dev);
inet_add_protocol(&ipip_protocol);
return 0; return 0;
} }
static void __exit ipip_fini(void) static void __exit ipip_fini(void)
{ {
if ( inet_del_protocol(&ipip_protocol) < 0 ) if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0)
printk(KERN_INFO "ipip close: can't remove protocol\n"); printk(KERN_INFO "ipip close: can't remove protocol\n");
unregister_netdev(&ipip_fb_tunnel_dev); unregister_netdev(&ipip_fb_tunnel_dev);
......
...@@ -108,7 +108,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local ...@@ -108,7 +108,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert); static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert);
static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm);
extern struct inet_protocol pim_protocol; static struct inet_protocol pim_protocol;
static struct timer_list ipmr_expire_timer; static struct timer_list ipmr_expire_timer;
...@@ -928,23 +928,28 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) ...@@ -928,23 +928,28 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen)
#ifdef CONFIG_IP_PIMSM #ifdef CONFIG_IP_PIMSM
case MRT_PIM: case MRT_PIM:
{ {
int v; int v, ret;
if(get_user(v,(int *)optval)) if(get_user(v,(int *)optval))
return -EFAULT; return -EFAULT;
v = (v)?1:0; v = (v)?1:0;
rtnl_lock(); rtnl_lock();
ret = 0;
if (v != mroute_do_pim) { if (v != mroute_do_pim) {
mroute_do_pim = v; mroute_do_pim = v;
mroute_do_assert = v; mroute_do_assert = v;
#ifdef CONFIG_IP_PIMSM_V2 #ifdef CONFIG_IP_PIMSM_V2
if (mroute_do_pim) if (mroute_do_pim)
inet_add_protocol(&pim_protocol); ret = inet_add_protocol(&pim_protocol,
IPPROTO_PIM);
else else
inet_del_protocol(&pim_protocol); ret = inet_del_protocol(&pim_protocol,
IPPROTO_PIM);
if (ret < 0)
ret = -EAGAIN;
#endif #endif
} }
rtnl_unlock(); rtnl_unlock();
return 0; return ret;
} }
#endif #endif
/* /*
...@@ -1727,15 +1732,8 @@ static int ipmr_mfc_info(char *buffer, char **start, off_t offset, int length) ...@@ -1727,15 +1732,8 @@ static int ipmr_mfc_info(char *buffer, char **start, off_t offset, int length)
#endif #endif
#ifdef CONFIG_IP_PIMSM_V2 #ifdef CONFIG_IP_PIMSM_V2
struct inet_protocol pim_protocol = static struct inet_protocol pim_protocol = {
{ .handler = pim_rcv,
pim_rcv, /* PIM handler */
NULL, /* PIM error control */
NULL, /* next */
IPPROTO_PIM, /* protocol ID */
0, /* copy */
NULL, /* data */
"PIM" /* name */
}; };
#endif #endif
......
...@@ -48,134 +48,52 @@ ...@@ -48,134 +48,52 @@
#include <net/ipip.h> #include <net/ipip.h>
#include <linux/igmp.h> #include <linux/igmp.h>
#define IPPROTO_PREVIOUS NULL
#ifdef CONFIG_IP_MULTICAST
static struct inet_protocol igmp_protocol = {
.handler = igmp_rcv,
.next = IPPROTO_PREVIOUS,
.protocol = IPPROTO_IGMP,
.name = "IGMP"
};
#undef IPPROTO_PREVIOUS
#define IPPROTO_PREVIOUS &igmp_protocol
#endif
static struct inet_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.next = IPPROTO_PREVIOUS,
.protocol = IPPROTO_TCP,
.name = "TCP"
};
#undef IPPROTO_PREVIOUS
#define IPPROTO_PREVIOUS &tcp_protocol
static struct inet_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
.next = IPPROTO_PREVIOUS,
.protocol = IPPROTO_UDP,
.name = "UDP"
};
#undef IPPROTO_PREVIOUS
#define IPPROTO_PREVIOUS &udp_protocol
static struct inet_protocol icmp_protocol = {
.handler = icmp_rcv,
.next = IPPROTO_PREVIOUS,
.protocol = IPPROTO_ICMP,
.name = "ICMP"
};
#undef IPPROTO_PREVIOUS
#define IPPROTO_PREVIOUS &icmp_protocol
struct inet_protocol *inet_protocol_base = IPPROTO_PREVIOUS;
struct inet_protocol *inet_protos[MAX_INET_PROTOS]; struct inet_protocol *inet_protos[MAX_INET_PROTOS];
/* /*
* Add a protocol handler to the hash tables * Add a protocol handler to the hash tables
*/ */
void inet_add_protocol(struct inet_protocol *prot) int inet_add_protocol(struct inet_protocol *prot, unsigned char protocol)
{ {
unsigned char hash; int hash, ret;
struct inet_protocol *p2;
hash = protocol & (MAX_INET_PROTOS - 1);
hash = prot->protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK); br_write_lock_bh(BR_NETPROTO_LOCK);
prot ->next = inet_protos[hash];
inet_protos[hash] = prot;
prot->copy = 0;
/* if (inet_protos[hash]) {
* Set the copy bit if we need to. ret = -1;
*/ } else {
inet_protos[hash] = prot;
p2 = (struct inet_protocol *) prot->next; ret = 0;
while (p2) {
if (p2->protocol == prot->protocol) {
prot->copy = 1;
break;
}
p2 = (struct inet_protocol *) p2->next;
} }
br_write_unlock_bh(BR_NETPROTO_LOCK); br_write_unlock_bh(BR_NETPROTO_LOCK);
return ret;
} }
/* /*
* Remove a protocol from the hash tables. * Remove a protocol from the hash tables.
*/ */
int inet_del_protocol(struct inet_protocol *prot) int inet_del_protocol(struct inet_protocol *prot, unsigned char protocol)
{ {
struct inet_protocol *p; int hash, ret;
struct inet_protocol *lp = NULL;
unsigned char hash;
hash = prot->protocol & (MAX_INET_PROTOS - 1); hash = protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK);
if (prot == inet_protos[hash]) {
inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
br_write_unlock_bh(BR_NETPROTO_LOCK);
return 0;
}
p = (struct inet_protocol *) inet_protos[hash]; br_write_lock_bh(BR_NETPROTO_LOCK);
if (p != NULL && p->protocol == prot->protocol)
lp = p;
while (p) {
/*
* We have to worry if the protocol being deleted is
* the last one on the list, then we may need to reset
* someone's copied bit.
*/
if (p->next && p->next == prot) {
/*
* if we are the last one with this protocol and
* there is a previous one, reset its copy bit.
*/
if (prot->copy == 0 && lp != NULL)
lp->copy = 0;
p->next = prot->next;
br_write_unlock_bh(BR_NETPROTO_LOCK);
return 0;
}
if (p->next != NULL && p->next->protocol == prot->protocol)
lp = p->next;
p = (struct inet_protocol *) p->next; if (inet_protos[hash] == prot) {
inet_protos[hash] = NULL;
ret = 0;
} else {
ret = -1;
} }
br_write_unlock_bh(BR_NETPROTO_LOCK); br_write_unlock_bh(BR_NETPROTO_LOCK);
return -1;
return ret;
} }
...@@ -135,13 +135,12 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb) ...@@ -135,13 +135,12 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
} }
/* IP input processing comes here for RAW socket delivery. /* IP input processing comes here for RAW socket delivery.
* This is fun as to avoid copies we want to make no surplus * Caller owns SKB, so we must make clones.
* copies.
* *
* RFC 1122: SHOULD pass TOS value up to the transport layer. * RFC 1122: SHOULD pass TOS value up to the transport layer.
* -> It does. And not only TOS, but all IP header. * -> It does. And not only TOS, but all IP header.
*/ */
struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
{ {
struct sock *sk; struct sock *sk;
...@@ -153,28 +152,19 @@ struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) ...@@ -153,28 +152,19 @@ struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
skb->dev->ifindex); skb->dev->ifindex);
while (sk) { while (sk) {
struct sock *sknext = __raw_v4_lookup(sk->next, iph->protocol, if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) {
iph->saddr, iph->daddr, struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
skb->dev->ifindex);
if (iph->protocol != IPPROTO_ICMP ||
!icmp_filter(sk, skb)) {
struct sk_buff *clone;
if (!sknext)
break;
clone = skb_clone(skb, GFP_ATOMIC);
/* Not releasing hash table! */ /* Not releasing hash table! */
if (clone) if (clone)
raw_rcv(sk, clone); raw_rcv(sk, clone);
} }
sk = sknext; sk = __raw_v4_lookup(sk->next, iph->protocol,
iph->saddr, iph->daddr,
skb->dev->ifindex);
} }
out: out:
if (sk)
sock_hold(sk);
read_unlock(&raw_v4_lock); read_unlock(&raw_v4_lock);
return sk;
} }
void raw_err (struct sock *sk, struct sk_buff *skb, u32 info) void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
......
...@@ -70,15 +70,8 @@ struct socket *icmpv6_socket; ...@@ -70,15 +70,8 @@ struct socket *icmpv6_socket;
static int icmpv6_rcv(struct sk_buff *skb); static int icmpv6_rcv(struct sk_buff *skb);
static struct inet6_protocol icmpv6_protocol = static struct inet6_protocol icmpv6_protocol = {
{ .handler = icmpv6_rcv,
icmpv6_rcv, /* handler */
NULL, /* error control */
NULL, /* next */
IPPROTO_ICMPV6, /* protocol ID */
0, /* copy */
NULL, /* data */
"ICMPv6" /* name */
}; };
struct icmpv6_msg { struct icmpv6_msg {
...@@ -467,15 +460,9 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) ...@@ -467,15 +460,9 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
hash = nexthdr & (MAX_INET_PROTOS - 1); hash = nexthdr & (MAX_INET_PROTOS - 1);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; ipprot = inet6_protos[hash];
ipprot != NULL; if (ipprot && ipprot->err_handler)
ipprot=(struct inet6_protocol *)ipprot->next) { ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
if (ipprot->protocol != nexthdr)
continue;
if (ipprot->err_handler)
ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
}
read_lock(&raw_v6_lock); read_lock(&raw_v6_lock);
if ((sk = raw_v6_htable[hash]) != NULL) { if ((sk = raw_v6_htable[hash]) != NULL) {
...@@ -651,7 +638,12 @@ int __init icmpv6_init(struct net_proto_family *ops) ...@@ -651,7 +638,12 @@ int __init icmpv6_init(struct net_proto_family *ops)
sk->sndbuf = SK_WMEM_MAX*2; sk->sndbuf = SK_WMEM_MAX*2;
sk->prot->unhash(sk); sk->prot->unhash(sk);
inet6_add_protocol(&icmpv6_protocol); if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) {
printk(KERN_ERR "Failed to register ICMP6 protocol\n");
sock_release(icmpv6_socket);
icmpv6_socket = NULL;
return -EAGAIN;
}
return 0; return 0;
} }
...@@ -660,7 +652,7 @@ void icmpv6_cleanup(void) ...@@ -660,7 +652,7 @@ void icmpv6_cleanup(void)
{ {
sock_release(icmpv6_socket); sock_release(icmpv6_socket);
icmpv6_socket = NULL; /* For safety. */ icmpv6_socket = NULL; /* For safety. */
inet6_del_protocol(&icmpv6_protocol); inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
} }
static struct icmp6_err { static struct icmp6_err {
......
...@@ -126,7 +126,6 @@ static inline int ip6_input_finish(struct sk_buff *skb) ...@@ -126,7 +126,6 @@ static inline int ip6_input_finish(struct sk_buff *skb)
struct sock *raw_sk; struct sock *raw_sk;
int nhoff; int nhoff;
int nexthdr; int nexthdr;
int found = 0;
u8 hash; u8 hash;
skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr); skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
...@@ -164,39 +163,24 @@ static inline int ip6_input_finish(struct sk_buff *skb) ...@@ -164,39 +163,24 @@ static inline int ip6_input_finish(struct sk_buff *skb)
skb->csum = csum_sub(skb->csum, skb->csum = csum_sub(skb->csum,
csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0)); csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)]; resubmit:
raw_sk = raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)];
if (raw_sk) if (raw_sk)
raw_sk = ipv6_raw_deliver(skb, nexthdr); ipv6_raw_deliver(skb, nexthdr);
hash = nexthdr & (MAX_INET_PROTOS - 1); hash = nexthdr & (MAX_INET_PROTOS - 1);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; if ((ipprot = inet6_protos[hash]) != NULL) {
ipprot != NULL; int ret = ipprot->handler(skb);
ipprot = (struct inet6_protocol *) ipprot->next) { if (ret < 0) {
struct sk_buff *buff = skb; nexthdr = -ret;
goto resubmit;
if (ipprot->protocol != nexthdr) }
continue; } else {
if (!raw_sk) {
if (ipprot->copy || raw_sk) IP6_INC_STATS_BH(Ip6InUnknownProtos);
buff = skb_clone(skb, GFP_ATOMIC); icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
}
if (buff) kfree_skb(skb);
ipprot->handler(buff);
found = 1;
}
if (raw_sk) {
rawv6_rcv(raw_sk, skb);
sock_put(raw_sk);
found = 1;
}
/*
* not found: send ICMP parameter problem back
*/
if (!found) {
IP6_INC_STATS_BH(Ip6InUnknownProtos);
icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
} }
return 0; return 0;
......
...@@ -42,77 +42,42 @@ ...@@ -42,77 +42,42 @@
struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
void inet6_add_protocol(struct inet6_protocol *prot) int inet6_add_protocol(struct inet6_protocol *prot, unsigned char protocol)
{ {
unsigned char hash; int ret, hash = protocol & (MAX_INET_PROTOS - 1);
struct inet6_protocol *p2;
hash = prot->protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK); br_write_lock_bh(BR_NETPROTO_LOCK);
prot->next = inet6_protos[hash];
inet6_protos[hash] = prot;
prot->copy = 0;
/* if (inet6_protos[hash]) {
* Set the copy bit if we need to. ret = -1;
*/ } else {
inet6_protos[hash] = prot;
p2 = (struct inet6_protocol *) prot->next; ret = 0;
while(p2 != NULL) {
if (p2->protocol == prot->protocol) {
prot->copy = 1;
break;
}
p2 = (struct inet6_protocol *) p2->next;
} }
br_write_unlock_bh(BR_NETPROTO_LOCK); br_write_unlock_bh(BR_NETPROTO_LOCK);
return ret;
} }
/* /*
* Remove a protocol from the hash tables. * Remove a protocol from the hash tables.
*/ */
int inet6_del_protocol(struct inet6_protocol *prot) int inet6_del_protocol(struct inet6_protocol *prot, unsigned char protocol)
{ {
struct inet6_protocol *p; int ret, hash = protocol & (MAX_INET_PROTOS - 1);
struct inet6_protocol *lp = NULL;
unsigned char hash;
hash = prot->protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK); br_write_lock_bh(BR_NETPROTO_LOCK);
if (prot == inet6_protos[hash]) {
inet6_protos[hash] = (struct inet6_protocol *) inet6_protos[hash]->next;
br_write_unlock_bh(BR_NETPROTO_LOCK);
return(0);
}
p = (struct inet6_protocol *) inet6_protos[hash];
if (p != NULL && p->protocol == prot->protocol) if (inet6_protos[hash] != prot) {
lp = p; ret = -1;
} else {
while(p != NULL) { inet6_protos[hash] = NULL;
/* ret = 0;
* We have to worry if the protocol being deleted is
* the last one on the list, then we may need to reset
* someone's copied bit.
*/
if (p->next != NULL && p->next == prot) {
/*
* if we are the last one with this protocol and
* there is a previous one, reset its copy bit.
*/
if (prot->copy == 0 && lp != NULL)
lp->copy = 0;
p->next = prot->next;
br_write_unlock_bh(BR_NETPROTO_LOCK);
return(0);
}
if (p->next != NULL && p->next->protocol == prot->protocol)
lp = p->next;
p = (struct inet6_protocol *) p->next;
} }
br_write_unlock_bh(BR_NETPROTO_LOCK); br_write_unlock_bh(BR_NETPROTO_LOCK);
return(-1);
return ret;
} }
...@@ -133,12 +133,14 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb) ...@@ -133,12 +133,14 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
* demultiplex raw sockets. * demultiplex raw sockets.
* (should consider queueing the skb in the sock receive_queue * (should consider queueing the skb in the sock receive_queue
* without calling rawv6.c) * without calling rawv6.c)
*
* Caller owns SKB so we must make clones.
*/ */
struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
{ {
struct in6_addr *saddr; struct in6_addr *saddr;
struct in6_addr *daddr; struct in6_addr *daddr;
struct sock *sk, *sk2; struct sock *sk;
__u8 hash; __u8 hash;
saddr = &skb->nh.ipv6h->saddr; saddr = &skb->nh.ipv6h->saddr;
...@@ -159,30 +161,18 @@ struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) ...@@ -159,30 +161,18 @@ struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr); sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);
if (sk) { while (sk) {
sk2 = sk; if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
while ((sk2 = __raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {
struct sk_buff *buff;
if (nexthdr == IPPROTO_ICMPV6 &&
icmpv6_filter(sk2, skb))
continue;
buff = skb_clone(skb, GFP_ATOMIC); /* Not releasing hash table! */
if (buff) if (clone)
rawv6_rcv(sk2, buff); rawv6_rcv(sk, clone);
} }
sk = __raw_v6_lookup(sk->next, nexthdr, daddr, saddr);
} }
if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
sk = NULL;
out: out:
if (sk)
sock_hold(sk);
read_unlock(&raw_v6_lock); read_unlock(&raw_v6_lock);
return sk;
} }
/* This cleans up af_inet6 a bit. -DaveM */ /* This cleans up af_inet6 a bit. -DaveM */
......
...@@ -835,19 +835,14 @@ int __init ipip6_fb_tunnel_init(struct net_device *dev) ...@@ -835,19 +835,14 @@ int __init ipip6_fb_tunnel_init(struct net_device *dev)
} }
static struct inet_protocol sit_protocol = { static struct inet_protocol sit_protocol = {
ipip6_rcv, .handler = ipip6_rcv,
ipip6_err, .err_handler = ipip6_err,
0,
IPPROTO_IPV6,
0,
NULL,
"IPv6"
}; };
#ifdef MODULE #ifdef MODULE
void sit_cleanup(void) void sit_cleanup(void)
{ {
inet_del_protocol(&sit_protocol); inet_del_protocol(&sit_protocol, IPPROTO_IPV6);
unregister_netdev(&ipip6_fb_tunnel_dev); unregister_netdev(&ipip6_fb_tunnel_dev);
} }
#endif #endif
...@@ -856,9 +851,13 @@ int __init sit_init(void) ...@@ -856,9 +851,13 @@ int __init sit_init(void)
{ {
printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n");
if (inet_add_protocol(&sit_protocol, IPPROTO_IPV6) < 0) {
printk(KERN_INFO "sit init: Can't add protocol\n");
return -EAGAIN;
}
ipip6_fb_tunnel_dev.priv = (void*)&ipip6_fb_tunnel; ipip6_fb_tunnel_dev.priv = (void*)&ipip6_fb_tunnel;
strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name); strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name);
register_netdev(&ipip6_fb_tunnel_dev); register_netdev(&ipip6_fb_tunnel_dev);
inet_add_protocol(&sit_protocol);
return 0; return 0;
} }
...@@ -2156,12 +2156,9 @@ struct proto tcpv6_prot = { ...@@ -2156,12 +2156,9 @@ struct proto tcpv6_prot = {
.get_port = tcp_v6_get_port, .get_port = tcp_v6_get_port,
}; };
static struct inet6_protocol tcpv6_protocol = static struct inet6_protocol tcpv6_protocol = {
{ .handler = tcp_v6_rcv,
.handler = tcp_v6_rcv, .err_handler = tcp_v6_err,
.err_handler = tcp_v6_err,
.protocol = IPPROTO_TCP,
.name = "TCPv6",
}; };
extern struct proto_ops inet6_stream_ops; extern struct proto_ops inet6_stream_ops;
...@@ -2179,6 +2176,7 @@ static struct inet_protosw tcpv6_protosw = { ...@@ -2179,6 +2176,7 @@ static struct inet_protosw tcpv6_protosw = {
void __init tcpv6_init(void) void __init tcpv6_init(void)
{ {
/* register inet6 protocol */ /* register inet6 protocol */
inet6_add_protocol(&tcpv6_protocol); if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
inet6_register_protosw(&tcpv6_protosw); inet6_register_protosw(&tcpv6_protosw);
} }
...@@ -907,10 +907,8 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen) ...@@ -907,10 +907,8 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
} }
static struct inet6_protocol udpv6_protocol = { static struct inet6_protocol udpv6_protocol = {
.handler = udpv6_rcv, .handler = udpv6_rcv,
.err_handler = udpv6_err, .err_handler = udpv6_err,
.protocol = IPPROTO_UDP,
.name = "UDPv6",
}; };
#define LINE_LEN 190 #define LINE_LEN 190
...@@ -1020,6 +1018,7 @@ static struct inet_protosw udpv6_protosw = { ...@@ -1020,6 +1018,7 @@ static struct inet_protosw udpv6_protosw = {
void __init udpv6_init(void) void __init udpv6_init(void)
{ {
inet6_add_protocol(&udpv6_protocol); if (inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP) < 0)
printk(KERN_ERR "udpv6_init: Could not register protocol\n");
inet6_register_protosw(&udpv6_protosw); inet6_register_protosw(&udpv6_protosw);
} }
...@@ -295,11 +295,6 @@ static struct inet_protosw sctpv6_protosw = { ...@@ -295,11 +295,6 @@ static struct inet_protosw sctpv6_protosw = {
static struct inet6_protocol sctpv6_protocol = { static struct inet6_protocol sctpv6_protocol = {
.handler = sctp_rcv, .handler = sctp_rcv,
.err_handler = sctp_v6_err, .err_handler = sctp_v6_err,
.next = NULL,
.protocol = IPPROTO_SCTP,
.copy = 0,
.data = NULL,
.name = "SCTPv6"
}; };
static sctp_func_t sctp_ipv6_specific = { static sctp_func_t sctp_ipv6_specific = {
...@@ -320,10 +315,12 @@ static sctp_pf_t sctp_pf_inet6_specific = { ...@@ -320,10 +315,12 @@ static sctp_pf_t sctp_pf_inet6_specific = {
/* Initialize IPv6 support and register with inet6 stack. */ /* Initialize IPv6 support and register with inet6 stack. */
int sctp_v6_init(void) int sctp_v6_init(void)
{ {
/* Register inet6 protocol. */
if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
return -EAGAIN;
/* Add SCTPv6 to inetsw6 linked list. */ /* Add SCTPv6 to inetsw6 linked list. */
inet6_register_protosw(&sctpv6_protosw); inet6_register_protosw(&sctpv6_protosw);
/* Register inet6 protocol. */
inet6_add_protocol(&sctpv6_protocol);
/* Register the SCTP specfic PF_INET6 functions. */ /* Register the SCTP specfic PF_INET6 functions. */
sctp_set_pf_specific(PF_INET6, &sctp_pf_inet6_specific); sctp_set_pf_specific(PF_INET6, &sctp_pf_inet6_specific);
...@@ -339,6 +336,6 @@ int sctp_v6_init(void) ...@@ -339,6 +336,6 @@ int sctp_v6_init(void)
void sctp_v6_exit(void) void sctp_v6_exit(void)
{ {
list_del(&sctp_ipv6_specific.list); list_del(&sctp_ipv6_specific.list);
inet6_del_protocol(&sctpv6_protocol); inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
inet6_unregister_protosw(&sctpv6_protosw); inet6_unregister_protosw(&sctpv6_protosw);
} }
...@@ -434,10 +434,8 @@ struct inet_protosw sctp_protosw = { ...@@ -434,10 +434,8 @@ struct inet_protosw sctp_protosw = {
/* Register with IP layer. */ /* Register with IP layer. */
static struct inet_protocol sctp_protocol = { static struct inet_protocol sctp_protocol = {
.handler = sctp_rcv, /* SCTP input handler. */ .handler = sctp_rcv,
.err_handler = sctp_v4_err, /* SCTP error control */ .err_handler = sctp_v4_err,
.protocol = IPPROTO_SCTP, /* protocol ID */
.name = "SCTP" /* name */
}; };
/* IPv4 address related functions. */ /* IPv4 address related functions. */
...@@ -485,12 +483,13 @@ int sctp_init(void) ...@@ -485,12 +483,13 @@ int sctp_init(void)
int i; int i;
int status = 0; int status = 0;
/* Add SCTP to inet_protos hash table. */
if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
return -EAGAIN;
/* Add SCTP to inetsw linked list. */ /* Add SCTP to inetsw linked list. */
inet_register_protosw(&sctp_protosw); inet_register_protosw(&sctp_protosw);
/* Add SCTP to inet_protos hash table. */
inet_add_protocol(&sctp_protocol);
/* Initialize proc fs directory. */ /* Initialize proc fs directory. */
sctp_proc_init(); sctp_proc_init();
...@@ -626,7 +625,7 @@ int sctp_init(void) ...@@ -626,7 +625,7 @@ int sctp_init(void)
err_ahash_alloc: err_ahash_alloc:
sctp_dbg_objcnt_exit(); sctp_dbg_objcnt_exit();
sctp_proc_exit(); sctp_proc_exit();
inet_del_protocol(&sctp_protocol); inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_protosw); inet_unregister_protosw(&sctp_protosw);
return status; return status;
} }
...@@ -656,7 +655,7 @@ void sctp_exit(void) ...@@ -656,7 +655,7 @@ void sctp_exit(void)
sctp_dbg_objcnt_exit(); sctp_dbg_objcnt_exit();
sctp_proc_exit(); sctp_proc_exit();
inet_del_protocol(&sctp_protocol); inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_protosw); inet_unregister_protosw(&sctp_protosw);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment