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

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

parent 8f6174bf
......@@ -30,7 +30,7 @@
#include <linux/ipv6.h>
#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. */
......@@ -38,11 +38,6 @@ struct inet_protocol
{
int (*handler)(struct sk_buff *skb);
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)
......@@ -54,11 +49,6 @@ struct inet6_protocol
struct inet6_skb_parm *opt,
int type, int code, int offset,
__u32 info);
struct inet6_protocol *next;
unsigned char protocol;
unsigned char copy:1;
void *data;
const char *name;
};
#endif
......@@ -93,14 +83,14 @@ extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
extern struct list_head inetsw6[SOCK_MAX];
#endif
extern void inet_add_protocol(struct inet_protocol *prot);
extern int inet_del_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, unsigned char num);
extern void inet_register_protosw(struct inet_protosw *p);
extern void inet_unregister_protosw(struct inet_protosw *p);
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
extern void inet6_add_protocol(struct inet6_protocol *prot);
extern int inet6_del_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, unsigned char num);
extern void inet6_register_protosw(struct inet_protosw *p);
extern void inet6_unregister_protosw(struct inet_protosw *p);
#endif
......
......@@ -37,6 +37,6 @@ extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
unsigned long raddr, unsigned long laddr,
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 */
......@@ -7,9 +7,7 @@
extern struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
extern rwlock_t raw_v6_lock;
extern struct sock * ipv6_raw_deliver(struct sk_buff *skb,
int nexthdr);
extern void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
struct in6_addr *loc_addr, struct in6_addr *rmt_addr);
......
......@@ -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.
......@@ -1101,7 +1120,6 @@ void inet_unregister_protosw(struct inet_protosw *p)
static int __init inet_init(void)
{
struct sk_buff *dummy_skb;
struct inet_protocol *p;
struct inet_protosw *q;
struct list_head *r;
......@@ -1131,16 +1149,19 @@ static int __init inet_init(void)
(void)sock_register(&inet_family_ops);
/*
* Add all the protocols.
* Add all the base protocols.
*/
printk(KERN_INFO "IP Protocols: ");
for (p = inet_protocol_base; p;) {
struct inet_protocol *tmp = (struct inet_protocol *)p->next;
inet_add_protocol(p);
printk("%s%s", p->name, tmp ? ", " : "\n");
p = tmp;
}
if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
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. */
for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
......
......@@ -719,23 +719,10 @@ static void icmp_unreach(struct sk_buff *skb)
* we are OK.
*/
ipprot = (struct inet_protocol *)inet_protos[hash];
while (ipprot) {
struct inet_protocol *nextip;
ipprot = inet_protos[hash];
if (ipprot && ipprot->err_handler)
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:
return;
out_err:
......
......@@ -1259,13 +1259,8 @@ int __init ipgre_fb_tunnel_init(struct net_device *dev)
static struct inet_protocol ipgre_protocol = {
ipgre_rcv, /* GRE handler */
ipgre_err, /* TUNNEL error control */
0, /* next */
IPPROTO_GRE, /* protocol ID */
0, /* copy */
NULL, /* data */
"GRE" /* name */
.handler = ipgre_rcv,
.err_handler = ipgre_err,
};
......@@ -1281,9 +1276,13 @@ int __init ipgre_init(void)
{
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;
register_netdev(&ipgre_fb_tunnel_dev);
inet_add_protocol(&ipgre_protocol);
return 0;
}
......@@ -1291,7 +1290,7 @@ int __init ipgre_init(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");
unregister_netdev(&ipgre_fb_tunnel_dev);
......
......@@ -194,28 +194,6 @@ int ip_call_ra_chain(struct sk_buff *skb)
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)
{
int ihl = skb->nh.iph->ihl*4;
......@@ -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 */
int protocol = skb->nh.iph->protocol;
int hash = protocol & (MAX_INET_PROTOS - 1);
struct sock *raw_sk = raw_v4_htable[hash];
int hash;
struct sock *raw_sk;
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
* don't care less
*/
if(raw_sk != NULL)
raw_sk = raw_v4_input(skb, skb->nh.iph, hash);
ipprot = (struct inet_protocol *) inet_protos[hash];
flag = 0;
if(ipprot != NULL) {
if(raw_sk == NULL &&
ipprot->next == NULL &&
ipprot->protocol == protocol) {
int ret;
/* Fast path... */
ret = ipprot->handler(skb);
return ret;
} else {
flag = ip_run_ipprot(skb, skb->nh.iph, ipprot, (raw_sk != NULL));
if (raw_sk)
raw_v4_input(skb, skb->nh.iph, hash);
if ((ipprot = inet_protos[hash]) != NULL) {
int ret = ipprot->handler(skb);
if (ret < 0) {
protocol = -ret;
goto resubmit;
}
} else {
if (!raw_sk) {
icmp_send(skb, ICMP_DEST_UNREACH,
ICMP_PROT_UNREACH, 0);
}
}
/* 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);
}
}
......
......@@ -877,10 +877,8 @@ int __init ipip_fb_tunnel_init(struct net_device *dev)
}
static struct inet_protocol ipip_protocol = {
.handler = ipip_rcv,
.err_handler = ipip_err,
.protocol = IPPROTO_IPIP,
.name = "IPIP"
.handler = ipip_rcv,
.err_handler = ipip_err,
};
static char banner[] __initdata =
......@@ -890,15 +888,19 @@ int __init ipip_init(void)
{
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;
register_netdev(&ipip_fb_tunnel_dev);
inet_add_protocol(&ipip_protocol);
return 0;
}
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");
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
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);
extern struct inet_protocol pim_protocol;
static struct inet_protocol pim_protocol;
static struct timer_list ipmr_expire_timer;
......@@ -928,23 +928,28 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen)
#ifdef CONFIG_IP_PIMSM
case MRT_PIM:
{
int v;
int v, ret;
if(get_user(v,(int *)optval))
return -EFAULT;
v = (v)?1:0;
rtnl_lock();
ret = 0;
if (v != mroute_do_pim) {
mroute_do_pim = v;
mroute_do_assert = v;
#ifdef CONFIG_IP_PIMSM_V2
if (mroute_do_pim)
inet_add_protocol(&pim_protocol);
ret = inet_add_protocol(&pim_protocol,
IPPROTO_PIM);
else
inet_del_protocol(&pim_protocol);
ret = inet_del_protocol(&pim_protocol,
IPPROTO_PIM);
if (ret < 0)
ret = -EAGAIN;
#endif
}
rtnl_unlock();
return 0;
return ret;
}
#endif
/*
......@@ -1727,15 +1732,8 @@ static int ipmr_mfc_info(char *buffer, char **start, off_t offset, int length)
#endif
#ifdef CONFIG_IP_PIMSM_V2
struct inet_protocol pim_protocol =
{
pim_rcv, /* PIM handler */
NULL, /* PIM error control */
NULL, /* next */
IPPROTO_PIM, /* protocol ID */
0, /* copy */
NULL, /* data */
"PIM" /* name */
static struct inet_protocol pim_protocol = {
.handler = pim_rcv,
};
#endif
......
......@@ -48,134 +48,52 @@
#include <net/ipip.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];
/*
* 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;
struct inet_protocol *p2;
int hash, ret;
hash = protocol & (MAX_INET_PROTOS - 1);
hash = prot->protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK);
prot ->next = inet_protos[hash];
inet_protos[hash] = prot;
prot->copy = 0;
/*
* Set the copy bit if we need to.
*/
p2 = (struct inet_protocol *) prot->next;
while (p2) {
if (p2->protocol == prot->protocol) {
prot->copy = 1;
break;
}
p2 = (struct inet_protocol *) p2->next;
if (inet_protos[hash]) {
ret = -1;
} else {
inet_protos[hash] = prot;
ret = 0;
}
br_write_unlock_bh(BR_NETPROTO_LOCK);
return ret;
}
/*
* 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;
struct inet_protocol *lp = NULL;
unsigned char hash;
int hash, ret;
hash = prot->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;
}
hash = protocol & (MAX_INET_PROTOS - 1);
p = (struct inet_protocol *) inet_protos[hash];
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;
br_write_lock_bh(BR_NETPROTO_LOCK);
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);
return -1;
return ret;
}
......@@ -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.
* This is fun as to avoid copies we want to make no surplus
* copies.
* Caller owns SKB, so we must make clones.
*
* RFC 1122: SHOULD pass TOS value up to the transport layer.
* -> 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;
......@@ -153,28 +152,19 @@ struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
skb->dev->ifindex);
while (sk) {
struct sock *sknext = __raw_v4_lookup(sk->next, iph->protocol,
iph->saddr, iph->daddr,
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);
if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
/* Not releasing hash table! */
if (clone)
raw_rcv(sk, clone);
}
sk = sknext;
sk = __raw_v4_lookup(sk->next, iph->protocol,
iph->saddr, iph->daddr,
skb->dev->ifindex);
}
out:
if (sk)
sock_hold(sk);
read_unlock(&raw_v4_lock);
return sk;
}
void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
......
......@@ -70,15 +70,8 @@ struct socket *icmpv6_socket;
static int icmpv6_rcv(struct sk_buff *skb);
static struct inet6_protocol icmpv6_protocol =
{
icmpv6_rcv, /* handler */
NULL, /* error control */
NULL, /* next */
IPPROTO_ICMPV6, /* protocol ID */
0, /* copy */
NULL, /* data */
"ICMPv6" /* name */
static struct inet6_protocol icmpv6_protocol = {
.handler = icmpv6_rcv,
};
struct icmpv6_msg {
......@@ -467,15 +460,9 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
hash = nexthdr & (MAX_INET_PROTOS - 1);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
ipprot != NULL;
ipprot=(struct inet6_protocol *)ipprot->next) {
if (ipprot->protocol != nexthdr)
continue;
if (ipprot->err_handler)
ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
}
ipprot = inet6_protos[hash];
if (ipprot && ipprot->err_handler)
ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
read_lock(&raw_v6_lock);
if ((sk = raw_v6_htable[hash]) != NULL) {
......@@ -651,7 +638,12 @@ int __init icmpv6_init(struct net_proto_family *ops)
sk->sndbuf = SK_WMEM_MAX*2;
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;
}
......@@ -660,7 +652,7 @@ void icmpv6_cleanup(void)
{
sock_release(icmpv6_socket);
icmpv6_socket = NULL; /* For safety. */
inet6_del_protocol(&icmpv6_protocol);
inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
}
static struct icmp6_err {
......
......@@ -126,7 +126,6 @@ static inline int ip6_input_finish(struct sk_buff *skb)
struct sock *raw_sk;
int nhoff;
int nexthdr;
int found = 0;
u8 hash;
skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
......@@ -164,39 +163,24 @@ static inline int ip6_input_finish(struct sk_buff *skb)
skb->csum = csum_sub(skb->csum,
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)
raw_sk = ipv6_raw_deliver(skb, nexthdr);
ipv6_raw_deliver(skb, nexthdr);
hash = nexthdr & (MAX_INET_PROTOS - 1);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
ipprot != NULL;
ipprot = (struct inet6_protocol *) ipprot->next) {
struct sk_buff *buff = skb;
if (ipprot->protocol != nexthdr)
continue;
if (ipprot->copy || raw_sk)
buff = skb_clone(skb, GFP_ATOMIC);
if (buff)
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);
if ((ipprot = inet6_protos[hash]) != NULL) {
int ret = ipprot->handler(skb);
if (ret < 0) {
nexthdr = -ret;
goto resubmit;
}
} else {
if (!raw_sk) {
IP6_INC_STATS_BH(Ip6InUnknownProtos);
icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
}
kfree_skb(skb);
}
return 0;
......
......@@ -42,77 +42,42 @@
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;
struct inet6_protocol *p2;
int ret, hash = protocol & (MAX_INET_PROTOS - 1);
hash = prot->protocol & (MAX_INET_PROTOS - 1);
br_write_lock_bh(BR_NETPROTO_LOCK);
prot->next = inet6_protos[hash];
inet6_protos[hash] = prot;
prot->copy = 0;
/*
* Set the copy bit if we need to.
*/
p2 = (struct inet6_protocol *) prot->next;
while(p2 != NULL) {
if (p2->protocol == prot->protocol) {
prot->copy = 1;
break;
}
p2 = (struct inet6_protocol *) p2->next;
if (inet6_protos[hash]) {
ret = -1;
} else {
inet6_protos[hash] = prot;
ret = 0;
}
br_write_unlock_bh(BR_NETPROTO_LOCK);
return ret;
}
/*
* 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;
struct inet6_protocol *lp = NULL;
unsigned char hash;
int ret, hash = protocol & (MAX_INET_PROTOS - 1);
hash = prot->protocol & (MAX_INET_PROTOS - 1);
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)
lp = p;
while(p != NULL) {
/*
* 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;
if (inet6_protos[hash] != prot) {
ret = -1;
} else {
inet6_protos[hash] = NULL;
ret = 0;
}
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)
* demultiplex raw sockets.
* (should consider queueing the skb in the sock receive_queue
* 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 *daddr;
struct sock *sk, *sk2;
struct sock *sk;
__u8 hash;
saddr = &skb->nh.ipv6h->saddr;
......@@ -159,30 +161,18 @@ struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);
if (sk) {
sk2 = sk;
while ((sk2 = __raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {
struct sk_buff *buff;
if (nexthdr == IPPROTO_ICMPV6 &&
icmpv6_filter(sk2, skb))
continue;
while (sk) {
if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
buff = skb_clone(skb, GFP_ATOMIC);
if (buff)
rawv6_rcv(sk2, buff);
/* Not releasing hash table! */
if (clone)
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:
if (sk)
sock_hold(sk);
read_unlock(&raw_v6_lock);
return sk;
}
/* This cleans up af_inet6 a bit. -DaveM */
......
......@@ -835,19 +835,14 @@ int __init ipip6_fb_tunnel_init(struct net_device *dev)
}
static struct inet_protocol sit_protocol = {
ipip6_rcv,
ipip6_err,
0,
IPPROTO_IPV6,
0,
NULL,
"IPv6"
.handler = ipip6_rcv,
.err_handler = ipip6_err,
};
#ifdef MODULE
void sit_cleanup(void)
{
inet_del_protocol(&sit_protocol);
inet_del_protocol(&sit_protocol, IPPROTO_IPV6);
unregister_netdev(&ipip6_fb_tunnel_dev);
}
#endif
......@@ -856,9 +851,13 @@ int __init sit_init(void)
{
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;
strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name);
register_netdev(&ipip6_fb_tunnel_dev);
inet_add_protocol(&sit_protocol);
return 0;
}
......@@ -2156,12 +2156,9 @@ struct proto tcpv6_prot = {
.get_port = tcp_v6_get_port,
};
static struct inet6_protocol tcpv6_protocol =
{
.handler = tcp_v6_rcv,
.err_handler = tcp_v6_err,
.protocol = IPPROTO_TCP,
.name = "TCPv6",
static struct inet6_protocol tcpv6_protocol = {
.handler = tcp_v6_rcv,
.err_handler = tcp_v6_err,
};
extern struct proto_ops inet6_stream_ops;
......@@ -2179,6 +2176,7 @@ static struct inet_protosw tcpv6_protosw = {
void __init tcpv6_init(void)
{
/* 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);
}
......@@ -907,10 +907,8 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
}
static struct inet6_protocol udpv6_protocol = {
.handler = udpv6_rcv,
.err_handler = udpv6_err,
.protocol = IPPROTO_UDP,
.name = "UDPv6",
.handler = udpv6_rcv,
.err_handler = udpv6_err,
};
#define LINE_LEN 190
......@@ -1020,6 +1018,7 @@ static struct inet_protosw udpv6_protosw = {
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);
}
......@@ -295,11 +295,6 @@ static struct inet_protosw sctpv6_protosw = {
static struct inet6_protocol sctpv6_protocol = {
.handler = sctp_rcv,
.err_handler = sctp_v6_err,
.next = NULL,
.protocol = IPPROTO_SCTP,
.copy = 0,
.data = NULL,
.name = "SCTPv6"
};
static sctp_func_t sctp_ipv6_specific = {
......@@ -320,10 +315,12 @@ static sctp_pf_t sctp_pf_inet6_specific = {
/* Initialize IPv6 support and register with inet6 stack. */
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. */
inet6_register_protosw(&sctpv6_protosw);
/* Register inet6 protocol. */
inet6_add_protocol(&sctpv6_protocol);
/* Register the SCTP specfic PF_INET6 functions. */
sctp_set_pf_specific(PF_INET6, &sctp_pf_inet6_specific);
......@@ -339,6 +336,6 @@ int sctp_v6_init(void)
void sctp_v6_exit(void)
{
list_del(&sctp_ipv6_specific.list);
inet6_del_protocol(&sctpv6_protocol);
inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
inet6_unregister_protosw(&sctpv6_protosw);
}
......@@ -434,10 +434,8 @@ struct inet_protosw sctp_protosw = {
/* Register with IP layer. */
static struct inet_protocol sctp_protocol = {
.handler = sctp_rcv, /* SCTP input handler. */
.err_handler = sctp_v4_err, /* SCTP error control */
.protocol = IPPROTO_SCTP, /* protocol ID */
.name = "SCTP" /* name */
.handler = sctp_rcv,
.err_handler = sctp_v4_err,
};
/* IPv4 address related functions. */
......@@ -485,12 +483,13 @@ int sctp_init(void)
int i;
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. */
inet_register_protosw(&sctp_protosw);
/* Add SCTP to inet_protos hash table. */
inet_add_protocol(&sctp_protocol);
/* Initialize proc fs directory. */
sctp_proc_init();
......@@ -626,7 +625,7 @@ int sctp_init(void)
err_ahash_alloc:
sctp_dbg_objcnt_exit();
sctp_proc_exit();
inet_del_protocol(&sctp_protocol);
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_protosw);
return status;
}
......@@ -656,7 +655,7 @@ void sctp_exit(void)
sctp_dbg_objcnt_exit();
sctp_proc_exit();
inet_del_protocol(&sctp_protocol);
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
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