File: /usr/src/linux/net/ipv6/protocol.c

1     /*
2      * INET		An implementation of the TCP/IP protocol suite for the LINUX
3      *		operating system.  INET is implemented using the  BSD Socket
4      *		interface as the means of communication with the user level.
5      *
6      *		PF_INET6 protocol dispatch tables.
7      *
8      * Version:	$Id: protocol.c,v 1.10 2001/05/18 02:25:49 davem Exp $
9      *
10      * Authors:	Pedro Roque	<roque@di.fc.ul.pt>
11      *
12      *		This program is free software; you can redistribute it and/or
13      *		modify it under the terms of the GNU General Public License
14      *		as published by the Free Software Foundation; either version
15      *		2 of the License, or (at your option) any later version.
16      */
17     
18     /*
19      *      Changes:
20      *
21      *      Vince Laviano (vince@cs.stanford.edu)       16 May 2001
22      *      - Removed unused variable 'inet6_protocol_base'
23      *      - Modified inet6_del_protocol() to correctly maintain copy bit.
24      */
25     
26     #include <linux/errno.h>
27     #include <linux/types.h>
28     #include <linux/socket.h>
29     #include <linux/sockios.h>
30     #include <linux/sched.h>
31     #include <linux/net.h>
32     #include <linux/in6.h>
33     #include <linux/netdevice.h>
34     #include <linux/if_arp.h>
35     #include <linux/brlock.h>
36     
37     #include <net/sock.h>
38     #include <net/snmp.h>
39     
40     #include <net/ipv6.h>
41     #include <net/protocol.h>
42     
43     struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
44     
45     void inet6_add_protocol(struct inet6_protocol *prot)
46     {
47     	unsigned char hash;
48     	struct inet6_protocol *p2;
49     
50     	hash = prot->protocol & (MAX_INET_PROTOS - 1);
51     	br_write_lock_bh(BR_NETPROTO_LOCK);
52     	prot->next = inet6_protos[hash];
53     	inet6_protos[hash] = prot;
54     	prot->copy = 0;
55     
56     	/*
57     	 *	Set the copy bit if we need to. 
58     	 */
59     	 
60     	p2 = (struct inet6_protocol *) prot->next;
61     	while(p2 != NULL) {
62     		if (p2->protocol == prot->protocol) {
63     			prot->copy = 1;
64     			break;
65     		}
66     		p2 = (struct inet6_protocol *) p2->next;
67     	}
68     	br_write_unlock_bh(BR_NETPROTO_LOCK);
69     }
70     
71     /*
72      *	Remove a protocol from the hash tables.
73      */
74      
75     int inet6_del_protocol(struct inet6_protocol *prot)
76     {
77     	struct inet6_protocol *p;
78     	struct inet6_protocol *lp = NULL;
79     	unsigned char hash;
80     
81     	hash = prot->protocol & (MAX_INET_PROTOS - 1);
82     	br_write_lock_bh(BR_NETPROTO_LOCK);
83     	if (prot == inet6_protos[hash]) {
84     		inet6_protos[hash] = (struct inet6_protocol *) inet6_protos[hash]->next;
85     		br_write_unlock_bh(BR_NETPROTO_LOCK);
86     		return(0);
87     	}
88     
89     	p = (struct inet6_protocol *) inet6_protos[hash];
90     
91             if (p != NULL && p->protocol == prot->protocol)
92                     lp = p;
93     
94     	while(p != NULL) {
95     		/*
96     		 * We have to worry if the protocol being deleted is
97     		 * the last one on the list, then we may need to reset
98     		 * someone's copied bit.
99     		 */
100     		if (p->next != NULL && p->next == prot) {
101     			/*
102     			 * if we are the last one with this protocol and
103     			 * there is a previous one, reset its copy bit.
104     			 */
105     			if (prot->copy == 0 && lp != NULL)
106     				lp->copy = 0;
107     			p->next = prot->next;
108     			br_write_unlock_bh(BR_NETPROTO_LOCK);
109     			return(0);
110     		}
111     		if (p->next != NULL && p->next->protocol == prot->protocol) 
112     			lp = p->next;
113     
114     		p = (struct inet6_protocol *) p->next;
115     	}
116     	br_write_unlock_bh(BR_NETPROTO_LOCK);
117     	return(-1);
118     }
119