altq_afmap.c revision 1.4 1 /* $NetBSD: altq_afmap.c,v 1.4 2001/11/12 23:14:21 lukem Exp $ */
2 /* $KAME: altq_afmap.c,v 1.7 2000/12/14 08:12:45 thorpej Exp $ */
3
4 /*
5 * Copyright (C) 1997-2000
6 * Sony Computer Science Laboratories Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /*
31 * experimental:
32 * mapping an ip flow to atm vpi/vci.
33 * this module is not related to queueing at all, but uses the altq
34 * flowinfo mechanism. it's just put in the altq framework since
35 * it is easy to add devices to altq.
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: altq_afmap.c,v 1.4 2001/11/12 23:14:21 lukem Exp $");
40
41 #if defined(__FreeBSD__) || defined(__NetBSD__)
42 #include "opt_altq.h"
43 #if (__FreeBSD__ != 2)
44 #include "opt_inet.h"
45 #ifdef __FreeBSD__
46 #include "opt_inet6.h"
47 #endif
48 #endif
49 #endif /* __FreeBSD__ || __NetBSD__ */
50 #ifdef ALTQ_AFMAP
51
52 #include <sys/types.h>
53 #include <sys/param.h>
54 #include <sys/malloc.h>
55 #include <sys/mbuf.h>
56 #include <sys/uio.h>
57 #include <sys/socket.h>
58 #include <sys/systm.h>
59 #include <sys/proc.h>
60 #include <sys/errno.h>
61 #include <sys/time.h>
62 #include <sys/kernel.h>
63
64 #include <net/if.h>
65 #include <net/if_types.h>
66 #include <netinet/in.h>
67
68 #include <altq/altq.h>
69 #include <altq/altq_conf.h>
70 #include <altq/altq_afmap.h>
71
72 LIST_HEAD(, afm_head) afhead_chain;
73
74 static struct afm *afm_match4 __P((struct afm_head *, struct flowinfo_in *));
75 #ifdef INET6
76 static struct afm *afm_match6 __P((struct afm_head *, struct flowinfo_in6 *));
77 #endif
78
79 /*
80 * rules to block interrupts: afm_match can be called from a net
81 * level interrupt so that other routines handling the lists should
82 * be called in splnet().
83 */
84 int
85 afm_alloc(ifp)
86 struct ifnet *ifp;
87 {
88 struct afm_head *head;
89
90 MALLOC(head, struct afm_head *, sizeof(struct afm_head),
91 M_DEVBUF, M_WAITOK);
92 if (head == NULL)
93 panic("afm_alloc: malloc failed!");
94 bzero(head, sizeof(struct afm_head));
95
96 /* initialize per interface afmap list */
97 LIST_INIT(&head->afh_head);
98
99 head->afh_ifp = ifp;
100
101 /* add this afm_head to the chain */
102 LIST_INSERT_HEAD(&afhead_chain, head, afh_chain);
103
104 return (0);
105 }
106
107 int
108 afm_dealloc(ifp)
109 struct ifnet *ifp;
110 {
111 struct afm_head *head;
112
113 for (head = afhead_chain.lh_first; head != NULL;
114 head = head->afh_chain.le_next)
115 if (head->afh_ifp == ifp)
116 break;
117 if (head == NULL)
118 return (-1);
119
120 afm_removeall(ifp);
121
122 LIST_REMOVE(head, afh_chain);
123
124 FREE(head, M_DEVBUF);
125 return 0;
126 }
127
128 struct afm *
129 afm_top(ifp)
130 struct ifnet *ifp;
131 {
132 struct afm_head *head;
133
134 for (head = afhead_chain.lh_first; head != NULL;
135 head = head->afh_chain.le_next)
136 if (head->afh_ifp == ifp)
137 break;
138 if (head == NULL)
139 return NULL;
140
141 return (head->afh_head.lh_first);
142 }
143
144 int afm_add(ifp, flowmap)
145 struct ifnet *ifp;
146 struct atm_flowmap *flowmap;
147 {
148 struct afm_head *head;
149 struct afm *afm;
150
151 for (head = afhead_chain.lh_first; head != NULL;
152 head = head->afh_chain.le_next)
153 if (head->afh_ifp == ifp)
154 break;
155 if (head == NULL)
156 return (-1);
157
158 if (flowmap->af_flowinfo.fi_family == AF_INET) {
159 if (flowmap->af_flowinfo.fi_len != sizeof(struct flowinfo_in))
160 return (EINVAL);
161 #ifdef INET6
162 } else if (flowmap->af_flowinfo.fi_family == AF_INET6) {
163 if (flowmap->af_flowinfo.fi_len != sizeof(struct flowinfo_in6))
164 return (EINVAL);
165 #endif
166 } else
167 return (EINVAL);
168
169 MALLOC(afm, struct afm *, sizeof(struct afm),
170 M_DEVBUF, M_WAITOK);
171 if (afm == NULL)
172 return (ENOMEM);
173 bzero(afm, sizeof(struct afm));
174
175 afm->afm_vci = flowmap->af_vci;
176 afm->afm_vpi = flowmap->af_vpi;
177 bcopy(&flowmap->af_flowinfo, &afm->afm_flowinfo,
178 flowmap->af_flowinfo.fi_len);
179
180 LIST_INSERT_HEAD(&head->afh_head, afm, afm_list);
181 return 0;
182 }
183
184 int
185 afm_remove(afm)
186 struct afm *afm;
187 {
188 LIST_REMOVE(afm, afm_list);
189 FREE(afm, M_DEVBUF);
190 return (0);
191 }
192
193 int
194 afm_removeall(ifp)
195 struct ifnet *ifp;
196 {
197 struct afm_head *head;
198 struct afm *afm;
199
200 for (head = afhead_chain.lh_first; head != NULL;
201 head = head->afh_chain.le_next)
202 if (head->afh_ifp == ifp)
203 break;
204 if (head == NULL)
205 return (-1);
206
207 while ((afm = head->afh_head.lh_first) != NULL)
208 afm_remove(afm);
209 return (0);
210 }
211
212 struct afm *
213 afm_lookup(ifp, vpi, vci)
214 struct ifnet *ifp;
215 int vpi, vci;
216 {
217 struct afm_head *head;
218 struct afm *afm;
219
220 for (head = afhead_chain.lh_first; head != NULL;
221 head = head->afh_chain.le_next)
222 if (head->afh_ifp == ifp)
223 break;
224 if (head == NULL)
225 return NULL;
226
227 for (afm = head->afh_head.lh_first; afm != NULL;
228 afm = afm->afm_list.le_next)
229 if (afm->afm_vpi == vpi && afm->afm_vci == vci)
230 break;
231 return afm;
232 }
233
234 static struct afm *
235 afm_match4(head, fp)
236 struct afm_head *head;
237 struct flowinfo_in *fp;
238 {
239 struct afm *afm;
240
241 for (afm = head->afh_head.lh_first; afm != NULL;
242 afm = afm->afm_list.le_next) {
243 if (afm->afm_flowinfo4.fi_dst.s_addr != 0 &&
244 afm->afm_flowinfo4.fi_dst.s_addr != fp->fi_dst.s_addr)
245 continue;
246 if (afm->afm_flowinfo4.fi_dport != 0 &&
247 afm->afm_flowinfo4.fi_dport != fp->fi_dport)
248 continue;
249 if (afm->afm_flowinfo4.fi_src.s_addr != 0 &&
250 afm->afm_flowinfo4.fi_src.s_addr != fp->fi_src.s_addr)
251 continue;
252 if (afm->afm_flowinfo4.fi_sport != 0 &&
253 afm->afm_flowinfo4.fi_sport != fp->fi_sport)
254 continue;
255 if (afm->afm_flowinfo4.fi_proto != 0 &&
256 afm->afm_flowinfo4.fi_proto != fp->fi_proto)
257 continue;
258 /* match found! */
259 return (afm);
260 }
261 return NULL;
262 }
263
264 #ifdef INET6
265 static struct afm *
266 afm_match6(head, fp)
267 struct afm_head *head;
268 struct flowinfo_in6 *fp;
269 {
270 struct afm *afm;
271
272 for (afm = head->afh_head.lh_first; afm != NULL;
273 afm = afm->afm_list.le_next) {
274 if (afm->afm_flowinfo6.fi6_flowlabel != 0 &&
275 afm->afm_flowinfo6.fi6_flowlabel != fp->fi6_flowlabel)
276 continue;
277 #ifdef notyet
278 if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi6_dst) &&
279 !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi6_dst,
280 &fp->fi6_dst))
281 continue;
282 if (afm->afm_flowinfo6.fi6_dport != 0 &&
283 afm->afm_flowinfo6.fi6_dport != fp->fi6_dport)
284 continue;
285 #endif
286 if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi6_src) &&
287 !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi6_src,
288 &fp->fi6_src))
289 continue;
290 #ifdef notyet
291 if (afm->afm_flowinfo6.fi6_sport != 0 &&
292 afm->afm_flowinfo6.fi6_sport != fp->fi6_sport)
293 continue;
294 #endif
295 if (afm->afm_flowinfo6.fi6_proto != 0 &&
296 afm->afm_flowinfo6.fi6_proto != fp->fi6_proto)
297 continue;
298 /* match found! */
299 return (afm);
300 }
301 return NULL;
302 }
303 #endif
304
305 /* should be called in splnet() */
306 struct afm *
307 afm_match(ifp, flow)
308 struct ifnet *ifp;
309 struct flowinfo *flow;
310 {
311 struct afm_head *head;
312
313 for (head = afhead_chain.lh_first; head != NULL;
314 head = head->afh_chain.le_next)
315 if (head->afh_ifp == ifp)
316 break;
317 if (head == NULL)
318 return NULL;
319
320 switch (flow->fi_family) {
321 case AF_INET:
322 return (afm_match4(head, (struct flowinfo_in *)flow));
323
324 #ifdef INET6
325 case AF_INET6:
326 return (afm_match6(head, (struct flowinfo_in6 *)flow));
327 #endif
328
329 default:
330 return NULL;
331 }
332 }
333
334 /*
335 * afm device interface
336 */
337 altqdev_decl(afm);
338
339 int
340 afmopen(dev, flag, fmt, p)
341 dev_t dev;
342 int flag, fmt;
343 struct proc *p;
344 {
345 return 0;
346 }
347
348 int
349 afmclose(dev, flag, fmt, p)
350 dev_t dev;
351 int flag, fmt;
352 struct proc *p;
353 {
354 int err, error = 0;
355 struct atm_flowmap fmap;
356 struct afm_head *head;
357
358 for (head = afhead_chain.lh_first; head != NULL;
359 head = head->afh_chain.le_next) {
360
361 /* call interface to clean up maps */
362 #if defined(__NetBSD__) || defined(__OpenBSD__)
363 sprintf(fmap.af_ifname, "%s", head->afh_ifp->if_xname);
364 #else
365 sprintf(fmap.af_ifname, "%s%d",
366 head->afh_ifp->if_name, head->afh_ifp->if_unit);
367 #endif
368 err = afmioctl(dev, AFM_CLEANFMAP, (caddr_t)&fmap, flag, p);
369 if (err && error == 0)
370 error = err;
371 }
372
373 return error;
374 }
375
376 int
377 afmioctl(dev, cmd, addr, flag, p)
378 dev_t dev;
379 ioctlcmd_t cmd;
380 caddr_t addr;
381 int flag;
382 struct proc *p;
383 {
384 int error = 0;
385 struct atm_flowmap *flowmap;
386 struct ifnet *ifp;
387
388 /* check cmd for superuser only */
389 switch (cmd) {
390 case AFM_GETFMAP:
391 break;
392 default:
393 #if (__FreeBSD_version > 400000)
394 error = suser(p);
395 #else
396 error = suser(p->p_ucred, &p->p_acflag);
397 #endif
398 if (error)
399 return (error);
400 break;
401 }
402
403 /* lookup interface */
404 flowmap = (struct atm_flowmap *)addr;
405 flowmap->af_ifname[IFNAMSIZ-1] = '\0';
406 ifp = ifunit(flowmap->af_ifname);
407 if (ifp == NULL || ifp->if_ioctl == NULL ||
408 (ifp->if_flags & IFF_RUNNING) == 0)
409 error = ENXIO;
410 else
411 error = ifp->if_ioctl(ifp, cmd, addr);
412
413 return error;
414 }
415
416 #endif /* ALTQ_AFMAP */
417