This source file includes following definitions.
- vif_delete
- ip_mroute_setsockopt
- ip_mroute_getsockopt
- ipmr_ioctl
- mroute_close
- ipmr_device_event
- ip_mr_init
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <asm/system.h>
14 #include <asm/segment.h>
15 #include <linux/types.h>
16 #include <linux/sched.h>
17 #include <linux/errno.h>
18 #include <linux/timer.h>
19 #include <linux/mm.h>
20 #include <linux/kernel.h>
21 #include <linux/fcntl.h>
22 #include <linux/socket.h>
23 #include <linux/in.h>
24 #include <linux/inet.h>
25 #include <linux/netdevice.h>
26 #include <linux/mroute.h>
27 #include <net/ip.h>
28 #include <net/protocol.h>
29 #include <linux/skbuff.h>
30 #include <net/sock.h>
31 #include <net/icmp.h>
32 #include <net/udp.h>
33 #include <linux/notifier.h>
34 #include <net/checksum.h>
35
36 #ifdef CONFIG_IP_MROUTE
37
38
39
40
41
42 static struct vif_device vif_table[MAXVIFS];
43 static unsigned long vifc_map;
44 int mroute_do_pim = 0;
45
46
47
48
49
50 static void vif_delete(struct vif_device *v)
51 {
52 if(!(v->flags&VIFF_TUNNEL))
53 {
54 v->dev->flags&=~IFF_ALLMULTI;
55 dev_mc_upload(v->dev);
56 }
57 v->dev=NULL;
58 }
59
60
61
62
63
64
65
66
67 int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen)
68 {
69 int err;
70 struct vifctl vif;
71
72 if(optname!=MRT_INIT)
73 {
74 if(sk!=mroute_socket)
75 return -EACCES;
76 }
77
78 switch(optname)
79 {
80 case MRT_INIT:
81 if(sk->type!=SOCK_RAW || sk->num!=IPPROTO_IGMP)
82 return -EOPNOTSUPP;
83 if(optlen!=sizeof(int))
84 return -ENOPROTOOPT;
85 if((err=verify_area(VERIFY_READ,optval,sizeof(int)))<0)
86 return err;
87 if(get_user((int *)optval)!=1)
88 return -ENOPROTOOPT;
89 if(mroute_socket)
90 return -EADDRINUSE;
91 mroute_socket=sk;
92
93 return 0;
94 case MRT_DONE:
95 mroute_close(sk);
96 mroute_socket=NULL;
97 return 0;
98 case MRT_ADD_VIF:
99 case MRT_DEL_VIF:
100 if(optlen!=sizeof(vif))
101 return -EINVAL;
102 if((err=verify_area(VERIFY_READ, optval, sizeof(vif)))<0)
103 return err;
104 memcpy_fromfs(&vif,optval,sizeof(vif));
105 if(vif.vifc_vifi > MAXVIFS)
106 return -ENFILE;
107 if(optname==MRT_ADD_VIF)
108 {
109 struct vif_device *v=&vif_table[vif.vifc_vifi];
110 struct device *dev;
111
112 if(vifc_map&(1<<vif.vifc_vifi))
113 return -EADDRINUSE;
114
115 dev=ip_dev_find(vif.vifc_lcl_addr.s_addr);
116 if(!dev)
117 return -EADDRNOTAVAIL;
118
119 if(vif.vifc_flags&VIFF_TUNNEL)
120 {
121 if(vif.vifc_flags&VIFF_SRCRT)
122 return -EOPNOTSUPP;
123
124 }
125 else
126 {
127 if(dev->flags&IFF_MULTICAST)
128 {
129
130
131 dev->flags|=IFF_ALLMULTI;
132 dev_mc_upload(dev);
133 }
134 else
135 {
136
137 return -EOPNOTSUPP;
138 }
139 }
140
141
142
143 cli();
144 v->rate_limit=vif.vifc_rate_limit;
145 v->local=vif.vifc_lcl_addr.s_addr;
146 v->remote=vif.vifc_rmt_addr.s_addr;
147 v->flags=vif.vifc_flags;
148 v->threshold=vif.vifc_threshold;
149 v->dev=dev;
150 v->bytes_in = 0;
151 v->bytes_out = 0;
152 v->pkt_in = 0;
153 v->pkt_out = 0;
154 vifc_map|=(1<<vif.vifc_vifi);
155 sti();
156 return 0;
157 }
158 else
159
160
161
162 {
163 struct vif_device *v=&vif_table[vif.vifc_vifi];
164 if(vifc_map&(1<<vif.vifc_vifi))
165 {
166 vif_delete(v);
167 vifc_map&=~(1<<vif.vifc_vifi);
168 return 0;
169 }
170 else
171 return -EADDRNOTAVAIL;
172 }
173
174
175
176
177 case MRT_ADD_MFC:
178 case MRT_DEL_MFC:
179 return -EOPNOTSUPP;
180
181
182
183 case MRT_ASSERT:
184 if(optlen!=sizeof(int))
185 return -EINVAL;
186 if((err=verify_area(VERIFY_READ, optval,sizeof(int)))<0)
187 return err;
188 mroute_do_pim= (optval)?1:0;
189 return 0;
190
191
192
193
194 default:
195 return -EOPNOTSUPP;
196 }
197 }
198
199
200
201
202
203 int ip_mroute_getsockopt(struct sock *sk,int optname,char *optval,int *optlen)
204 {
205 int olr;
206 int err;
207
208 if(sk!=mroute_socket)
209 return -EACCES;
210 if(optname!=MRT_VERSION && optname!=MRT_ASSERT)
211 return -EOPNOTSUPP;
212
213 olr=get_user(optlen);
214 if(olr!=sizeof(int))
215 return -EINVAL;
216 err=verify_area(VERIFY_WRITE, optval,sizeof(int));
217 if(err)
218 return err;
219 put_user(sizeof(int),optlen);
220 if(optname==MRT_VERSION)
221 put_user(0x0305,(int *)optval);
222 else
223 put_user(mroute_do_pim,(int *)optval);
224 return 0;
225 }
226
227
228
229
230
231 int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg)
232 {
233 int err;
234 struct sioc_sg_req sr;
235 struct sioc_vif_req vr;
236 struct vif_device *vif;
237
238 switch(cmd)
239 {
240 case SIOCGETVIFCNT:
241 err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(vr));
242 if(err)
243 return err;
244 memcpy_fromfs(&vr,(void *)arg,sizeof(sr));
245 if(vr.vifi>=MAXVIFS)
246 return -EINVAL;
247 vif=&vif_table[vr.vifi];
248 if(vifc_map&(1<<vr.vifi))
249 {
250 vr.icount=vif->pkt_in;
251 vr.ocount=vif->pkt_out;
252 vr.ibytes=vif->bytes_in;
253 vr.obytes=vif->bytes_out;
254 memcpy_tofs((void *)arg,&vr,sizeof(sr));
255 return 0;
256 }
257 return -EADDRNOTAVAIL;
258 case SIOCGETSGCNT:
259 err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(sr));
260 if(err)
261 return err;
262 memcpy_fromfs(&sr,(void *)arg,sizeof(sr));
263 memcpy_tofs((void *)arg,&sr,sizeof(sr));
264 return 0;
265 default:
266 return -EINVAL;
267 }
268 }
269
270
271
272
273
274 void mroute_close(struct sock *sk)
275 {
276 int i;
277 struct vif_device *v=&vif_table[0];
278
279
280
281
282
283 for(i=0;i<MAXVIFS;i++)
284 {
285 if(vifc_map&(1<<i))
286 {
287 if(!(v->flags&VIFF_TUNNEL))
288 {
289 v->dev->flags&=~IFF_ALLMULTI;
290 dev_mc_upload(v->dev);
291 }
292 }
293 v++;
294 }
295 vifc_map=0;
296 }
297
298 static int ipmr_device_event(unsigned long event, void *ptr)
299 {
300 struct vif_device *v;
301 int ct;
302 if(event!=NETDEV_DOWN)
303 return NOTIFY_DONE;
304 v=&vif_table[0];
305 for(ct=0;ct<MAXVIFS;ct++)
306 {
307 if((vifc_map&(1<<ct)) && v->dev==ptr)
308 {
309 vif_delete(v);
310 vifc_map&=~(1<<ct);
311 }
312 v++;
313 }
314 return NOTIFY_DONE;
315 }
316
317
318 static struct notifier_block ip_mr_notifier={
319 ipmr_device_event,
320 NULL,
321 0
322 };
323
324
325 void ip_mr_init(void)
326 {
327 printk("Linux IP multicast router 0.00pre-working 8)\n");
328 register_netdevice_notifier(&ip_mr_notifier);
329 }
330
331 #endif