diff options
author | Cyrill Gorcunov <gorcunov@gmail.com> | 2009-01-21 18:55:35 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-21 18:55:35 -0500 |
commit | 273ec51dd7ceaa76e038875d85061ec856d8905e (patch) | |
tree | 41d73e3a6363c88b7f4fe44ab7713682dace51e9 /drivers/net/ppp_generic.c | |
parent | 4e9fb8016a351b5b9da7fea32bcfdbc9d836e421 (diff) |
net: ppp_generic - introduce net-namespace functionality v2
- Each namespace contains ppp channels and units separately
with appropriate locks
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ppp_generic.c')
-rw-r--r-- | drivers/net/ppp_generic.c | 275 |
1 files changed, 198 insertions, 77 deletions
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 7b2728b8f1b7..4405a76ed3da 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c | |||
@@ -49,6 +49,10 @@ | |||
49 | #include <net/slhc_vj.h> | 49 | #include <net/slhc_vj.h> |
50 | #include <asm/atomic.h> | 50 | #include <asm/atomic.h> |
51 | 51 | ||
52 | #include <linux/nsproxy.h> | ||
53 | #include <net/net_namespace.h> | ||
54 | #include <net/netns/generic.h> | ||
55 | |||
52 | #define PPP_VERSION "2.4.2" | 56 | #define PPP_VERSION "2.4.2" |
53 | 57 | ||
54 | /* | 58 | /* |
@@ -131,6 +135,7 @@ struct ppp { | |||
131 | struct sock_filter *active_filter;/* filter for pkts to reset idle */ | 135 | struct sock_filter *active_filter;/* filter for pkts to reset idle */ |
132 | unsigned pass_len, active_len; | 136 | unsigned pass_len, active_len; |
133 | #endif /* CONFIG_PPP_FILTER */ | 137 | #endif /* CONFIG_PPP_FILTER */ |
138 | struct net *ppp_net; /* the net we belong to */ | ||
134 | }; | 139 | }; |
135 | 140 | ||
136 | /* | 141 | /* |
@@ -155,6 +160,7 @@ struct channel { | |||
155 | struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */ | 160 | struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */ |
156 | spinlock_t downl; /* protects `chan', file.xq dequeue */ | 161 | spinlock_t downl; /* protects `chan', file.xq dequeue */ |
157 | struct ppp *ppp; /* ppp unit we're connected to */ | 162 | struct ppp *ppp; /* ppp unit we're connected to */ |
163 | struct net *chan_net; /* the net channel belongs to */ | ||
158 | struct list_head clist; /* link in list of channels per unit */ | 164 | struct list_head clist; /* link in list of channels per unit */ |
159 | rwlock_t upl; /* protects `ppp' */ | 165 | rwlock_t upl; /* protects `ppp' */ |
160 | #ifdef CONFIG_PPP_MULTILINK | 166 | #ifdef CONFIG_PPP_MULTILINK |
@@ -173,26 +179,35 @@ struct channel { | |||
173 | * channel.downl. | 179 | * channel.downl. |
174 | */ | 180 | */ |
175 | 181 | ||
176 | /* | ||
177 | * all_ppp_mutex protects the all_ppp_units mapping. | ||
178 | * It also ensures that finding a ppp unit in the all_ppp_units map | ||
179 | * and updating its file.refcnt field is atomic. | ||
180 | */ | ||
181 | static DEFINE_MUTEX(all_ppp_mutex); | ||
182 | static atomic_t ppp_unit_count = ATOMIC_INIT(0); | 182 | static atomic_t ppp_unit_count = ATOMIC_INIT(0); |
183 | static DEFINE_IDR(ppp_units_idr); | ||
184 | |||
185 | /* | ||
186 | * all_channels_lock protects all_channels and last_channel_index, | ||
187 | * and the atomicity of find a channel and updating its file.refcnt | ||
188 | * field. | ||
189 | */ | ||
190 | static DEFINE_SPINLOCK(all_channels_lock); | ||
191 | static LIST_HEAD(all_channels); | ||
192 | static LIST_HEAD(new_channels); | ||
193 | static int last_channel_index; | ||
194 | static atomic_t channel_count = ATOMIC_INIT(0); | 183 | static atomic_t channel_count = ATOMIC_INIT(0); |
195 | 184 | ||
185 | /* per-net private data for this module */ | ||
186 | static unsigned int ppp_net_id; | ||
187 | struct ppp_net { | ||
188 | /* units to ppp mapping */ | ||
189 | struct idr units_idr; | ||
190 | |||
191 | /* | ||
192 | * all_ppp_mutex protects the units_idr mapping. | ||
193 | * It also ensures that finding a ppp unit in the units_idr | ||
194 | * map and updating its file.refcnt field is atomic. | ||
195 | */ | ||
196 | struct mutex all_ppp_mutex; | ||
197 | |||
198 | /* channels */ | ||
199 | struct list_head all_channels; | ||
200 | struct list_head new_channels; | ||
201 | int last_channel_index; | ||
202 | |||
203 | /* | ||
204 | * all_channels_lock protects all_channels and | ||
205 | * last_channel_index, and the atomicity of find | ||
206 | * a channel and updating its file.refcnt field. | ||
207 | */ | ||
208 | spinlock_t all_channels_lock; | ||
209 | }; | ||
210 | |||
196 | /* Get the PPP protocol number from a skb */ | 211 | /* Get the PPP protocol number from a skb */ |
197 | #define PPP_PROTO(skb) (((skb)->data[0] << 8) + (skb)->data[1]) | 212 | #define PPP_PROTO(skb) (((skb)->data[0] << 8) + (skb)->data[1]) |
198 | 213 | ||
@@ -216,8 +231,8 @@ static atomic_t channel_count = ATOMIC_INIT(0); | |||
216 | #define seq_after(a, b) ((s32)((a) - (b)) > 0) | 231 | #define seq_after(a, b) ((s32)((a) - (b)) > 0) |
217 | 232 | ||
218 | /* Prototypes. */ | 233 | /* Prototypes. */ |
219 | static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, | 234 | static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, |
220 | unsigned int cmd, unsigned long arg); | 235 | struct file *file, unsigned int cmd, unsigned long arg); |
221 | static void ppp_xmit_process(struct ppp *ppp); | 236 | static void ppp_xmit_process(struct ppp *ppp); |
222 | static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); | 237 | static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); |
223 | static void ppp_push(struct ppp *ppp); | 238 | static void ppp_push(struct ppp *ppp); |
@@ -240,12 +255,12 @@ static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound); | |||
240 | static void ppp_ccp_closed(struct ppp *ppp); | 255 | static void ppp_ccp_closed(struct ppp *ppp); |
241 | static struct compressor *find_compressor(int type); | 256 | static struct compressor *find_compressor(int type); |
242 | static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); | 257 | static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); |
243 | static struct ppp *ppp_create_interface(int unit, int *retp); | 258 | static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp); |
244 | static void init_ppp_file(struct ppp_file *pf, int kind); | 259 | static void init_ppp_file(struct ppp_file *pf, int kind); |
245 | static void ppp_shutdown_interface(struct ppp *ppp); | 260 | static void ppp_shutdown_interface(struct ppp *ppp); |
246 | static void ppp_destroy_interface(struct ppp *ppp); | 261 | static void ppp_destroy_interface(struct ppp *ppp); |
247 | static struct ppp *ppp_find_unit(int unit); | 262 | static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit); |
248 | static struct channel *ppp_find_channel(int unit); | 263 | static struct channel *ppp_find_channel(struct ppp_net *pn, int unit); |
249 | static int ppp_connect_channel(struct channel *pch, int unit); | 264 | static int ppp_connect_channel(struct channel *pch, int unit); |
250 | static int ppp_disconnect_channel(struct channel *pch); | 265 | static int ppp_disconnect_channel(struct channel *pch); |
251 | static void ppp_destroy_channel(struct channel *pch); | 266 | static void ppp_destroy_channel(struct channel *pch); |
@@ -256,6 +271,14 @@ static void *unit_find(struct idr *p, int n); | |||
256 | 271 | ||
257 | static struct class *ppp_class; | 272 | static struct class *ppp_class; |
258 | 273 | ||
274 | /* per net-namespace data */ | ||
275 | static inline struct ppp_net *ppp_pernet(struct net *net) | ||
276 | { | ||
277 | BUG_ON(!net); | ||
278 | |||
279 | return net_generic(net, ppp_net_id); | ||
280 | } | ||
281 | |||
259 | /* Translates a PPP protocol number to a NP index (NP == network protocol) */ | 282 | /* Translates a PPP protocol number to a NP index (NP == network protocol) */ |
260 | static inline int proto_to_npindex(int proto) | 283 | static inline int proto_to_npindex(int proto) |
261 | { | 284 | { |
@@ -544,7 +567,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
544 | int __user *p = argp; | 567 | int __user *p = argp; |
545 | 568 | ||
546 | if (!pf) | 569 | if (!pf) |
547 | return ppp_unattached_ioctl(pf, file, cmd, arg); | 570 | return ppp_unattached_ioctl(current->nsproxy->net_ns, |
571 | pf, file, cmd, arg); | ||
548 | 572 | ||
549 | if (cmd == PPPIOCDETACH) { | 573 | if (cmd == PPPIOCDETACH) { |
550 | /* | 574 | /* |
@@ -763,12 +787,13 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
763 | return err; | 787 | return err; |
764 | } | 788 | } |
765 | 789 | ||
766 | static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, | 790 | static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, |
767 | unsigned int cmd, unsigned long arg) | 791 | struct file *file, unsigned int cmd, unsigned long arg) |
768 | { | 792 | { |
769 | int unit, err = -EFAULT; | 793 | int unit, err = -EFAULT; |
770 | struct ppp *ppp; | 794 | struct ppp *ppp; |
771 | struct channel *chan; | 795 | struct channel *chan; |
796 | struct ppp_net *pn; | ||
772 | int __user *p = (int __user *)arg; | 797 | int __user *p = (int __user *)arg; |
773 | 798 | ||
774 | lock_kernel(); | 799 | lock_kernel(); |
@@ -777,7 +802,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, | |||
777 | /* Create a new ppp unit */ | 802 | /* Create a new ppp unit */ |
778 | if (get_user(unit, p)) | 803 | if (get_user(unit, p)) |
779 | break; | 804 | break; |
780 | ppp = ppp_create_interface(unit, &err); | 805 | ppp = ppp_create_interface(net, unit, &err); |
781 | if (!ppp) | 806 | if (!ppp) |
782 | break; | 807 | break; |
783 | file->private_data = &ppp->file; | 808 | file->private_data = &ppp->file; |
@@ -792,29 +817,31 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, | |||
792 | /* Attach to an existing ppp unit */ | 817 | /* Attach to an existing ppp unit */ |
793 | if (get_user(unit, p)) | 818 | if (get_user(unit, p)) |
794 | break; | 819 | break; |
795 | mutex_lock(&all_ppp_mutex); | ||
796 | err = -ENXIO; | 820 | err = -ENXIO; |
797 | ppp = ppp_find_unit(unit); | 821 | pn = ppp_pernet(net); |
822 | mutex_lock(&pn->all_ppp_mutex); | ||
823 | ppp = ppp_find_unit(pn, unit); | ||
798 | if (ppp) { | 824 | if (ppp) { |
799 | atomic_inc(&ppp->file.refcnt); | 825 | atomic_inc(&ppp->file.refcnt); |
800 | file->private_data = &ppp->file; | 826 | file->private_data = &ppp->file; |
801 | err = 0; | 827 | err = 0; |
802 | } | 828 | } |
803 | mutex_unlock(&all_ppp_mutex); | 829 | mutex_unlock(&pn->all_ppp_mutex); |
804 | break; | 830 | break; |
805 | 831 | ||
806 | case PPPIOCATTCHAN: | 832 | case PPPIOCATTCHAN: |
807 | if (get_user(unit, p)) | 833 | if (get_user(unit, p)) |
808 | break; | 834 | break; |
809 | spin_lock_bh(&all_channels_lock); | ||
810 | err = -ENXIO; | 835 | err = -ENXIO; |
811 | chan = ppp_find_channel(unit); | 836 | pn = ppp_pernet(net); |
837 | spin_lock_bh(&pn->all_channels_lock); | ||
838 | chan = ppp_find_channel(pn, unit); | ||
812 | if (chan) { | 839 | if (chan) { |
813 | atomic_inc(&chan->file.refcnt); | 840 | atomic_inc(&chan->file.refcnt); |
814 | file->private_data = &chan->file; | 841 | file->private_data = &chan->file; |
815 | err = 0; | 842 | err = 0; |
816 | } | 843 | } |
817 | spin_unlock_bh(&all_channels_lock); | 844 | spin_unlock_bh(&pn->all_channels_lock); |
818 | break; | 845 | break; |
819 | 846 | ||
820 | default: | 847 | default: |
@@ -834,6 +861,51 @@ static const struct file_operations ppp_device_fops = { | |||
834 | .release = ppp_release | 861 | .release = ppp_release |
835 | }; | 862 | }; |
836 | 863 | ||
864 | static __net_init int ppp_init_net(struct net *net) | ||
865 | { | ||
866 | struct ppp_net *pn; | ||
867 | int err; | ||
868 | |||
869 | pn = kzalloc(sizeof(*pn), GFP_KERNEL); | ||
870 | if (!pn) | ||
871 | return -ENOMEM; | ||
872 | |||
873 | idr_init(&pn->units_idr); | ||
874 | mutex_init(&pn->all_ppp_mutex); | ||
875 | |||
876 | INIT_LIST_HEAD(&pn->all_channels); | ||
877 | INIT_LIST_HEAD(&pn->new_channels); | ||
878 | |||
879 | spin_lock_init(&pn->all_channels_lock); | ||
880 | |||
881 | err = net_assign_generic(net, ppp_net_id, pn); | ||
882 | if (err) { | ||
883 | kfree(pn); | ||
884 | return err; | ||
885 | } | ||
886 | |||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | static __net_exit void ppp_exit_net(struct net *net) | ||
891 | { | ||
892 | struct ppp_net *pn; | ||
893 | |||
894 | pn = net_generic(net, ppp_net_id); | ||
895 | idr_destroy(&pn->units_idr); | ||
896 | /* | ||
897 | * if someone has cached our net then | ||
898 | * further net_generic call will return NULL | ||
899 | */ | ||
900 | net_assign_generic(net, ppp_net_id, NULL); | ||
901 | kfree(pn); | ||
902 | } | ||
903 | |||
904 | static __net_initdata struct pernet_operations ppp_net_ops = { | ||
905 | .init = ppp_init_net, | ||
906 | .exit = ppp_exit_net, | ||
907 | }; | ||
908 | |||
837 | #define PPP_MAJOR 108 | 909 | #define PPP_MAJOR 108 |
838 | 910 | ||
839 | /* Called at boot time if ppp is compiled into the kernel, | 911 | /* Called at boot time if ppp is compiled into the kernel, |
@@ -843,25 +915,36 @@ static int __init ppp_init(void) | |||
843 | int err; | 915 | int err; |
844 | 916 | ||
845 | printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n"); | 917 | printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n"); |
846 | err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); | 918 | |
847 | if (!err) { | 919 | err = register_pernet_gen_device(&ppp_net_id, &ppp_net_ops); |
848 | ppp_class = class_create(THIS_MODULE, "ppp"); | 920 | if (err) { |
849 | if (IS_ERR(ppp_class)) { | 921 | printk(KERN_ERR "failed to register PPP pernet device (%d)\n", err); |
850 | err = PTR_ERR(ppp_class); | 922 | goto out; |
851 | goto out_chrdev; | ||
852 | } | ||
853 | device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, | ||
854 | "ppp"); | ||
855 | } | 923 | } |
856 | 924 | ||
857 | out: | 925 | err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); |
858 | if (err) | 926 | if (err) { |
859 | printk(KERN_ERR "failed to register PPP device (%d)\n", err); | 927 | printk(KERN_ERR "failed to register PPP device (%d)\n", err); |
860 | return err; | 928 | goto out_net; |
929 | } | ||
930 | |||
931 | ppp_class = class_create(THIS_MODULE, "ppp"); | ||
932 | if (IS_ERR(ppp_class)) { | ||
933 | err = PTR_ERR(ppp_class); | ||
934 | goto out_chrdev; | ||
935 | } | ||
936 | |||
937 | /* not a big deal if we fail here :-) */ | ||
938 | device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); | ||
939 | |||
940 | return 0; | ||
861 | 941 | ||
862 | out_chrdev: | 942 | out_chrdev: |
863 | unregister_chrdev(PPP_MAJOR, "ppp"); | 943 | unregister_chrdev(PPP_MAJOR, "ppp"); |
864 | goto out; | 944 | out_net: |
945 | unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops); | ||
946 | out: | ||
947 | return err; | ||
865 | } | 948 | } |
866 | 949 | ||
867 | /* | 950 | /* |
@@ -969,6 +1052,7 @@ static void ppp_setup(struct net_device *dev) | |||
969 | dev->tx_queue_len = 3; | 1052 | dev->tx_queue_len = 3; |
970 | dev->type = ARPHRD_PPP; | 1053 | dev->type = ARPHRD_PPP; |
971 | dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; | 1054 | dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; |
1055 | dev->features |= NETIF_F_NETNS_LOCAL; | ||
972 | } | 1056 | } |
973 | 1057 | ||
974 | /* | 1058 | /* |
@@ -1986,19 +2070,27 @@ ppp_mp_reconstruct(struct ppp *ppp) | |||
1986 | * Channel interface. | 2070 | * Channel interface. |
1987 | */ | 2071 | */ |
1988 | 2072 | ||
1989 | /* | 2073 | /* Create a new, unattached ppp channel. */ |
1990 | * Create a new, unattached ppp channel. | 2074 | int ppp_register_channel(struct ppp_channel *chan) |
1991 | */ | 2075 | { |
1992 | int | 2076 | return ppp_register_net_channel(current->nsproxy->net_ns, chan); |
1993 | ppp_register_channel(struct ppp_channel *chan) | 2077 | } |
2078 | |||
2079 | /* Create a new, unattached ppp channel for specified net. */ | ||
2080 | int ppp_register_net_channel(struct net *net, struct ppp_channel *chan) | ||
1994 | { | 2081 | { |
1995 | struct channel *pch; | 2082 | struct channel *pch; |
2083 | struct ppp_net *pn; | ||
1996 | 2084 | ||
1997 | pch = kzalloc(sizeof(struct channel), GFP_KERNEL); | 2085 | pch = kzalloc(sizeof(struct channel), GFP_KERNEL); |
1998 | if (!pch) | 2086 | if (!pch) |
1999 | return -ENOMEM; | 2087 | return -ENOMEM; |
2088 | |||
2089 | pn = ppp_pernet(net); | ||
2090 | |||
2000 | pch->ppp = NULL; | 2091 | pch->ppp = NULL; |
2001 | pch->chan = chan; | 2092 | pch->chan = chan; |
2093 | pch->chan_net = net; | ||
2002 | chan->ppp = pch; | 2094 | chan->ppp = pch; |
2003 | init_ppp_file(&pch->file, CHANNEL); | 2095 | init_ppp_file(&pch->file, CHANNEL); |
2004 | pch->file.hdrlen = chan->hdrlen; | 2096 | pch->file.hdrlen = chan->hdrlen; |
@@ -2008,11 +2100,13 @@ ppp_register_channel(struct ppp_channel *chan) | |||
2008 | init_rwsem(&pch->chan_sem); | 2100 | init_rwsem(&pch->chan_sem); |
2009 | spin_lock_init(&pch->downl); | 2101 | spin_lock_init(&pch->downl); |
2010 | rwlock_init(&pch->upl); | 2102 | rwlock_init(&pch->upl); |
2011 | spin_lock_bh(&all_channels_lock); | 2103 | |
2012 | pch->file.index = ++last_channel_index; | 2104 | spin_lock_bh(&pn->all_channels_lock); |
2013 | list_add(&pch->list, &new_channels); | 2105 | pch->file.index = ++pn->last_channel_index; |
2106 | list_add(&pch->list, &pn->new_channels); | ||
2014 | atomic_inc(&channel_count); | 2107 | atomic_inc(&channel_count); |
2015 | spin_unlock_bh(&all_channels_lock); | 2108 | spin_unlock_bh(&pn->all_channels_lock); |
2109 | |||
2016 | return 0; | 2110 | return 0; |
2017 | } | 2111 | } |
2018 | 2112 | ||
@@ -2053,9 +2147,11 @@ void | |||
2053 | ppp_unregister_channel(struct ppp_channel *chan) | 2147 | ppp_unregister_channel(struct ppp_channel *chan) |
2054 | { | 2148 | { |
2055 | struct channel *pch = chan->ppp; | 2149 | struct channel *pch = chan->ppp; |
2150 | struct ppp_net *pn; | ||
2056 | 2151 | ||
2057 | if (!pch) | 2152 | if (!pch) |
2058 | return; /* should never happen */ | 2153 | return; /* should never happen */ |
2154 | |||
2059 | chan->ppp = NULL; | 2155 | chan->ppp = NULL; |
2060 | 2156 | ||
2061 | /* | 2157 | /* |
@@ -2068,9 +2164,12 @@ ppp_unregister_channel(struct ppp_channel *chan) | |||
2068 | spin_unlock_bh(&pch->downl); | 2164 | spin_unlock_bh(&pch->downl); |
2069 | up_write(&pch->chan_sem); | 2165 | up_write(&pch->chan_sem); |
2070 | ppp_disconnect_channel(pch); | 2166 | ppp_disconnect_channel(pch); |
2071 | spin_lock_bh(&all_channels_lock); | 2167 | |
2168 | pn = ppp_pernet(pch->chan_net); | ||
2169 | spin_lock_bh(&pn->all_channels_lock); | ||
2072 | list_del(&pch->list); | 2170 | list_del(&pch->list); |
2073 | spin_unlock_bh(&all_channels_lock); | 2171 | spin_unlock_bh(&pn->all_channels_lock); |
2172 | |||
2074 | pch->file.dead = 1; | 2173 | pch->file.dead = 1; |
2075 | wake_up_interruptible(&pch->file.rwait); | 2174 | wake_up_interruptible(&pch->file.rwait); |
2076 | if (atomic_dec_and_test(&pch->file.refcnt)) | 2175 | if (atomic_dec_and_test(&pch->file.refcnt)) |
@@ -2395,9 +2494,10 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) | |||
2395 | * unit == -1 means allocate a new number. | 2494 | * unit == -1 means allocate a new number. |
2396 | */ | 2495 | */ |
2397 | static struct ppp * | 2496 | static struct ppp * |
2398 | ppp_create_interface(int unit, int *retp) | 2497 | ppp_create_interface(struct net *net, int unit, int *retp) |
2399 | { | 2498 | { |
2400 | struct ppp *ppp; | 2499 | struct ppp *ppp; |
2500 | struct ppp_net *pn; | ||
2401 | struct net_device *dev = NULL; | 2501 | struct net_device *dev = NULL; |
2402 | int ret = -ENOMEM; | 2502 | int ret = -ENOMEM; |
2403 | int i; | 2503 | int i; |
@@ -2406,6 +2506,8 @@ ppp_create_interface(int unit, int *retp) | |||
2406 | if (!dev) | 2506 | if (!dev) |
2407 | goto out1; | 2507 | goto out1; |
2408 | 2508 | ||
2509 | pn = ppp_pernet(net); | ||
2510 | |||
2409 | ppp = netdev_priv(dev); | 2511 | ppp = netdev_priv(dev); |
2410 | ppp->dev = dev; | 2512 | ppp->dev = dev; |
2411 | ppp->mru = PPP_MRU; | 2513 | ppp->mru = PPP_MRU; |
@@ -2421,17 +2523,23 @@ ppp_create_interface(int unit, int *retp) | |||
2421 | skb_queue_head_init(&ppp->mrq); | 2523 | skb_queue_head_init(&ppp->mrq); |
2422 | #endif /* CONFIG_PPP_MULTILINK */ | 2524 | #endif /* CONFIG_PPP_MULTILINK */ |
2423 | 2525 | ||
2526 | /* | ||
2527 | * drum roll: don't forget to set | ||
2528 | * the net device is belong to | ||
2529 | */ | ||
2530 | dev_net_set(dev, net); | ||
2531 | |||
2424 | ret = -EEXIST; | 2532 | ret = -EEXIST; |
2425 | mutex_lock(&all_ppp_mutex); | 2533 | mutex_lock(&pn->all_ppp_mutex); |
2426 | 2534 | ||
2427 | if (unit < 0) { | 2535 | if (unit < 0) { |
2428 | unit = unit_get(&ppp_units_idr, ppp); | 2536 | unit = unit_get(&pn->units_idr, ppp); |
2429 | if (unit < 0) { | 2537 | if (unit < 0) { |
2430 | *retp = unit; | 2538 | *retp = unit; |
2431 | goto out2; | 2539 | goto out2; |
2432 | } | 2540 | } |
2433 | } else { | 2541 | } else { |
2434 | if (unit_find(&ppp_units_idr, unit)) | 2542 | if (unit_find(&pn->units_idr, unit)) |
2435 | goto out2; /* unit already exists */ | 2543 | goto out2; /* unit already exists */ |
2436 | /* | 2544 | /* |
2437 | * if caller need a specified unit number | 2545 | * if caller need a specified unit number |
@@ -2442,7 +2550,7 @@ ppp_create_interface(int unit, int *retp) | |||
2442 | * fair but at least pppd will ask us to allocate | 2550 | * fair but at least pppd will ask us to allocate |
2443 | * new unit in this case so user is happy :) | 2551 | * new unit in this case so user is happy :) |
2444 | */ | 2552 | */ |
2445 | unit = unit_set(&ppp_units_idr, ppp, unit); | 2553 | unit = unit_set(&pn->units_idr, ppp, unit); |
2446 | if (unit < 0) | 2554 | if (unit < 0) |
2447 | goto out2; | 2555 | goto out2; |
2448 | } | 2556 | } |
@@ -2453,20 +2561,22 @@ ppp_create_interface(int unit, int *retp) | |||
2453 | 2561 | ||
2454 | ret = register_netdev(dev); | 2562 | ret = register_netdev(dev); |
2455 | if (ret != 0) { | 2563 | if (ret != 0) { |
2456 | unit_put(&ppp_units_idr, unit); | 2564 | unit_put(&pn->units_idr, unit); |
2457 | printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", | 2565 | printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", |
2458 | dev->name, ret); | 2566 | dev->name, ret); |
2459 | goto out2; | 2567 | goto out2; |
2460 | } | 2568 | } |
2461 | 2569 | ||
2570 | ppp->ppp_net = net; | ||
2571 | |||
2462 | atomic_inc(&ppp_unit_count); | 2572 | atomic_inc(&ppp_unit_count); |
2463 | mutex_unlock(&all_ppp_mutex); | 2573 | mutex_unlock(&pn->all_ppp_mutex); |
2464 | 2574 | ||
2465 | *retp = 0; | 2575 | *retp = 0; |
2466 | return ppp; | 2576 | return ppp; |
2467 | 2577 | ||
2468 | out2: | 2578 | out2: |
2469 | mutex_unlock(&all_ppp_mutex); | 2579 | mutex_unlock(&pn->all_ppp_mutex); |
2470 | free_netdev(dev); | 2580 | free_netdev(dev); |
2471 | out1: | 2581 | out1: |
2472 | *retp = ret; | 2582 | *retp = ret; |
@@ -2492,7 +2602,11 @@ init_ppp_file(struct ppp_file *pf, int kind) | |||
2492 | */ | 2602 | */ |
2493 | static void ppp_shutdown_interface(struct ppp *ppp) | 2603 | static void ppp_shutdown_interface(struct ppp *ppp) |
2494 | { | 2604 | { |
2495 | mutex_lock(&all_ppp_mutex); | 2605 | struct ppp_net *pn; |
2606 | |||
2607 | pn = ppp_pernet(ppp->ppp_net); | ||
2608 | mutex_lock(&pn->all_ppp_mutex); | ||
2609 | |||
2496 | /* This will call dev_close() for us. */ | 2610 | /* This will call dev_close() for us. */ |
2497 | ppp_lock(ppp); | 2611 | ppp_lock(ppp); |
2498 | if (!ppp->closing) { | 2612 | if (!ppp->closing) { |
@@ -2502,11 +2616,12 @@ static void ppp_shutdown_interface(struct ppp *ppp) | |||
2502 | } else | 2616 | } else |
2503 | ppp_unlock(ppp); | 2617 | ppp_unlock(ppp); |
2504 | 2618 | ||
2505 | unit_put(&ppp_units_idr, ppp->file.index); | 2619 | unit_put(&pn->units_idr, ppp->file.index); |
2506 | ppp->file.dead = 1; | 2620 | ppp->file.dead = 1; |
2507 | ppp->owner = NULL; | 2621 | ppp->owner = NULL; |
2508 | wake_up_interruptible(&ppp->file.rwait); | 2622 | wake_up_interruptible(&ppp->file.rwait); |
2509 | mutex_unlock(&all_ppp_mutex); | 2623 | |
2624 | mutex_unlock(&pn->all_ppp_mutex); | ||
2510 | } | 2625 | } |
2511 | 2626 | ||
2512 | /* | 2627 | /* |
@@ -2554,9 +2669,9 @@ static void ppp_destroy_interface(struct ppp *ppp) | |||
2554 | * The caller should have locked the all_ppp_mutex. | 2669 | * The caller should have locked the all_ppp_mutex. |
2555 | */ | 2670 | */ |
2556 | static struct ppp * | 2671 | static struct ppp * |
2557 | ppp_find_unit(int unit) | 2672 | ppp_find_unit(struct ppp_net *pn, int unit) |
2558 | { | 2673 | { |
2559 | return unit_find(&ppp_units_idr, unit); | 2674 | return unit_find(&pn->units_idr, unit); |
2560 | } | 2675 | } |
2561 | 2676 | ||
2562 | /* | 2677 | /* |
@@ -2568,20 +2683,22 @@ ppp_find_unit(int unit) | |||
2568 | * when we have a lot of channels in use. | 2683 | * when we have a lot of channels in use. |
2569 | */ | 2684 | */ |
2570 | static struct channel * | 2685 | static struct channel * |
2571 | ppp_find_channel(int unit) | 2686 | ppp_find_channel(struct ppp_net *pn, int unit) |
2572 | { | 2687 | { |
2573 | struct channel *pch; | 2688 | struct channel *pch; |
2574 | 2689 | ||
2575 | list_for_each_entry(pch, &new_channels, list) { | 2690 | list_for_each_entry(pch, &pn->new_channels, list) { |
2576 | if (pch->file.index == unit) { | 2691 | if (pch->file.index == unit) { |
2577 | list_move(&pch->list, &all_channels); | 2692 | list_move(&pch->list, &pn->all_channels); |
2578 | return pch; | 2693 | return pch; |
2579 | } | 2694 | } |
2580 | } | 2695 | } |
2581 | list_for_each_entry(pch, &all_channels, list) { | 2696 | |
2697 | list_for_each_entry(pch, &pn->all_channels, list) { | ||
2582 | if (pch->file.index == unit) | 2698 | if (pch->file.index == unit) |
2583 | return pch; | 2699 | return pch; |
2584 | } | 2700 | } |
2701 | |||
2585 | return NULL; | 2702 | return NULL; |
2586 | } | 2703 | } |
2587 | 2704 | ||
@@ -2592,11 +2709,14 @@ static int | |||
2592 | ppp_connect_channel(struct channel *pch, int unit) | 2709 | ppp_connect_channel(struct channel *pch, int unit) |
2593 | { | 2710 | { |
2594 | struct ppp *ppp; | 2711 | struct ppp *ppp; |
2712 | struct ppp_net *pn; | ||
2595 | int ret = -ENXIO; | 2713 | int ret = -ENXIO; |
2596 | int hdrlen; | 2714 | int hdrlen; |
2597 | 2715 | ||
2598 | mutex_lock(&all_ppp_mutex); | 2716 | pn = ppp_pernet(pch->chan_net); |
2599 | ppp = ppp_find_unit(unit); | 2717 | |
2718 | mutex_lock(&pn->all_ppp_mutex); | ||
2719 | ppp = ppp_find_unit(pn, unit); | ||
2600 | if (!ppp) | 2720 | if (!ppp) |
2601 | goto out; | 2721 | goto out; |
2602 | write_lock_bh(&pch->upl); | 2722 | write_lock_bh(&pch->upl); |
@@ -2620,7 +2740,7 @@ ppp_connect_channel(struct channel *pch, int unit) | |||
2620 | outl: | 2740 | outl: |
2621 | write_unlock_bh(&pch->upl); | 2741 | write_unlock_bh(&pch->upl); |
2622 | out: | 2742 | out: |
2623 | mutex_unlock(&all_ppp_mutex); | 2743 | mutex_unlock(&pn->all_ppp_mutex); |
2624 | return ret; | 2744 | return ret; |
2625 | } | 2745 | } |
2626 | 2746 | ||
@@ -2677,7 +2797,7 @@ static void __exit ppp_cleanup(void) | |||
2677 | unregister_chrdev(PPP_MAJOR, "ppp"); | 2797 | unregister_chrdev(PPP_MAJOR, "ppp"); |
2678 | device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); | 2798 | device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); |
2679 | class_destroy(ppp_class); | 2799 | class_destroy(ppp_class); |
2680 | idr_destroy(&ppp_units_idr); | 2800 | unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops); |
2681 | } | 2801 | } |
2682 | 2802 | ||
2683 | /* | 2803 | /* |
@@ -2743,6 +2863,7 @@ static void *unit_find(struct idr *p, int n) | |||
2743 | module_init(ppp_init); | 2863 | module_init(ppp_init); |
2744 | module_exit(ppp_cleanup); | 2864 | module_exit(ppp_cleanup); |
2745 | 2865 | ||
2866 | EXPORT_SYMBOL(ppp_register_net_channel); | ||
2746 | EXPORT_SYMBOL(ppp_register_channel); | 2867 | EXPORT_SYMBOL(ppp_register_channel); |
2747 | EXPORT_SYMBOL(ppp_unregister_channel); | 2868 | EXPORT_SYMBOL(ppp_unregister_channel); |
2748 | EXPORT_SYMBOL(ppp_channel_index); | 2869 | EXPORT_SYMBOL(ppp_channel_index); |