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