altq_afmap.c revision 1.13 1 /* $NetBSD: altq_afmap.c,v 1.13 2006/07/21 16:48:45 ad 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.13 2006/07/21 16:48:45 ad Exp $");
40
41 #ifdef _KERNEL_OPT
42 #include "opt_altq.h"
43 #include "opt_inet.h"
44 #endif
45
46 #include <sys/param.h>
47 #include <sys/malloc.h>
48 #include <sys/mbuf.h>
49 #include <sys/uio.h>
50 #include <sys/socket.h>
51 #include <sys/systm.h>
52 #include <sys/proc.h>
53 #include <sys/errno.h>
54 #include <sys/time.h>
55 #include <sys/kernel.h>
56 #include <sys/kauth.h>
57
58 #include <net/if.h>
59 #include <net/if_types.h>
60 #include <netinet/in.h>
61
62 #include <altq/altq.h>
63 #include <altq/altq_conf.h>
64 #include <altq/altq_afmap.h>
65
66 LIST_HEAD(, afm_head) afhead_chain;
67
68 static struct afm *afm_match4 __P((struct afm_head *, struct flowinfo_in *));
69 #ifdef INET6
70 static struct afm *afm_match6 __P((struct afm_head *, struct flowinfo_in6 *));
71 #endif
72
73 /*
74 * rules to block interrupts: afm_match can be called from a net
75 * level interrupt so that other routines handling the lists should
76 * be called in splnet().
77 */
78 int
79 afm_alloc(ifp)
80 struct ifnet *ifp;
81 {
82 struct afm_head *head;
83
84 head = malloc(sizeof(struct afm_head), M_DEVBUF, M_WAITOK|M_ZERO);
85 if (head == NULL)
86 panic("afm_alloc: malloc failed!");
87
88 /* initialize per interface afmap list */
89 LIST_INIT(&head->afh_head);
90
91 head->afh_ifp = ifp;
92
93 /* add this afm_head to the chain */
94 LIST_INSERT_HEAD(&afhead_chain, head, afh_chain);
95
96 return (0);
97 }
98
99 int
100 afm_dealloc(ifp)
101 struct ifnet *ifp;
102 {
103 struct afm_head *head;
104
105 for (head = afhead_chain.lh_first; head != NULL;
106 head = head->afh_chain.le_next)
107 if (head->afh_ifp == ifp)
108 break;
109 if (head == NULL)
110 return (-1);
111
112 afm_removeall(ifp);
113
114 LIST_REMOVE(head, afh_chain);
115
116 free(head, M_DEVBUF);
117 return 0;
118 }
119
120 struct afm *
121 afm_top(ifp)
122 struct ifnet *ifp;
123 {
124 struct afm_head *head;
125
126 for (head = afhead_chain.lh_first; head != NULL;
127 head = head->afh_chain.le_next)
128 if (head->afh_ifp == ifp)
129 break;
130 if (head == NULL)
131 return NULL;
132
133 return (head->afh_head.lh_first);
134 }
135
136 int afm_add(ifp, flowmap)
137 struct ifnet *ifp;
138 struct atm_flowmap *flowmap;
139 {
140 struct afm_head *head;
141 struct afm *afm;
142
143 for (head = afhead_chain.lh_first; head != NULL;
144 head = head->afh_chain.le_next)
145 if (head->afh_ifp == ifp)
146 break;
147 if (head == NULL)
148 return (-1);
149
150 if (flowmap->af_flowinfo.fi_family == AF_INET) {
151 if (flowmap->af_flowinfo.fi_len != sizeof(struct flowinfo_in))
152 return (EINVAL);
153 #ifdef INET6
154 } else if (flowmap->af_flowinfo.fi_family == AF_INET6) {
155 if (flowmap->af_flowinfo.fi_len != sizeof(struct flowinfo_in6))
156 return (EINVAL);
157 #endif
158 } else
159 return (EINVAL);
160
161 afm = malloc(sizeof(struct afm), M_DEVBUF, M_WAITOK|M_ZERO);
162 if (afm == NULL)
163 return (ENOMEM);
164
165 afm->afm_vci = flowmap->af_vci;
166 afm->afm_vpi = flowmap->af_vpi;
167 (void)memcpy(&afm->afm_flowinfo, &flowmap->af_flowinfo,
168 flowmap->af_flowinfo.fi_len);
169
170 LIST_INSERT_HEAD(&head->afh_head, afm, afm_list);
171 return 0;
172 }
173
174 int
175 afm_remove(afm)
176 struct afm *afm;
177 {
178 LIST_REMOVE(afm, afm_list);
179 free(afm, M_DEVBUF);
180 return (0);
181 }
182
183 int
184 afm_removeall(ifp)
185 struct ifnet *ifp;
186 {
187 struct afm_head *head;
188 struct afm *afm;
189
190 for (head = afhead_chain.lh_first; head != NULL;
191 head = head->afh_chain.le_next)
192 if (head->afh_ifp == ifp)
193 break;
194 if (head == NULL)
195 return (-1);
196
197 while ((afm = head->afh_head.lh_first) != NULL)
198 afm_remove(afm);
199 return (0);
200 }
201
202 struct afm *
203 afm_lookup(ifp, vpi, vci)
204 struct ifnet *ifp;
205 int vpi, vci;
206 {
207 struct afm_head *head;
208 struct afm *afm;
209
210 for (head = afhead_chain.lh_first; head != NULL;
211 head = head->afh_chain.le_next)
212 if (head->afh_ifp == ifp)
213 break;
214 if (head == NULL)
215 return NULL;
216
217 for (afm = head->afh_head.lh_first; afm != NULL;
218 afm = afm->afm_list.le_next)
219 if (afm->afm_vpi == vpi && afm->afm_vci == vci)
220 break;
221 return afm;
222 }
223
224 static struct afm *
225 afm_match4(head, fp)
226 struct afm_head *head;
227 struct flowinfo_in *fp;
228 {
229 struct afm *afm;
230
231 for (afm = head->afh_head.lh_first; afm != NULL;
232 afm = afm->afm_list.le_next) {
233 if (afm->afm_flowinfo4.fi_dst.s_addr != 0 &&
234 afm->afm_flowinfo4.fi_dst.s_addr != fp->fi_dst.s_addr)
235 continue;
236 if (afm->afm_flowinfo4.fi_dport != 0 &&
237 afm->afm_flowinfo4.fi_dport != fp->fi_dport)
238 continue;
239 if (afm->afm_flowinfo4.fi_src.s_addr != 0 &&
240 afm->afm_flowinfo4.fi_src.s_addr != fp->fi_src.s_addr)
241 continue;
242 if (afm->afm_flowinfo4.fi_sport != 0 &&
243 afm->afm_flowinfo4.fi_sport != fp->fi_sport)
244 continue;
245 if (afm->afm_flowinfo4.fi_proto != 0 &&
246 afm->afm_flowinfo4.fi_proto != fp->fi_proto)
247 continue;
248 /* match found! */
249 return (afm);
250 }
251 return NULL;
252 }
253
254 #ifdef INET6
255 static struct afm *
256 afm_match6(head, fp)
257 struct afm_head *head;
258 struct flowinfo_in6 *fp;
259 {
260 struct afm *afm;
261
262 for (afm = head->afh_head.lh_first; afm != NULL;
263 afm = afm->afm_list.le_next) {
264 if (afm->afm_flowinfo6.fi6_flowlabel != 0 &&
265 afm->afm_flowinfo6.fi6_flowlabel != fp->fi6_flowlabel)
266 continue;
267 #ifdef notyet
268 if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi6_dst) &&
269 !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi6_dst,
270 &fp->fi6_dst))
271 continue;
272 if (afm->afm_flowinfo6.fi6_dport != 0 &&
273 afm->afm_flowinfo6.fi6_dport != fp->fi6_dport)
274 continue;
275 #endif
276 if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi6_src) &&
277 !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi6_src,
278 &fp->fi6_src))
279 continue;
280 #ifdef notyet
281 if (afm->afm_flowinfo6.fi6_sport != 0 &&
282 afm->afm_flowinfo6.fi6_sport != fp->fi6_sport)
283 continue;
284 #endif
285 if (afm->afm_flowinfo6.fi6_proto != 0 &&
286 afm->afm_flowinfo6.fi6_proto != fp->fi6_proto)
287 continue;
288 /* match found! */
289 return (afm);
290 }
291 return NULL;
292 }
293 #endif
294
295 /* should be called in splnet() */
296 struct afm *
297 afm_match(ifp, flow)
298 struct ifnet *ifp;
299 struct flowinfo *flow;
300 {
301 struct afm_head *head;
302
303 for (head = afhead_chain.lh_first; head != NULL;
304 head = head->afh_chain.le_next)
305 if (head->afh_ifp == ifp)
306 break;
307 if (head == NULL)
308 return NULL;
309
310 switch (flow->fi_family) {
311 case AF_INET:
312 return (afm_match4(head, (struct flowinfo_in *)flow));
313
314 #ifdef INET6
315 case AF_INET6:
316 return (afm_match6(head, (struct flowinfo_in6 *)flow));
317 #endif
318
319 default:
320 return NULL;
321 }
322 }
323
324 /*
325 * afm device interface
326 */
327 altqdev_decl(afm);
328
329 int
330 afmopen(dev, flag, fmt, l)
331 dev_t dev;
332 int flag, fmt;
333 struct lwp *l;
334 {
335 return 0;
336 }
337
338 int
339 afmclose(dev, flag, fmt, l)
340 dev_t dev;
341 int flag, fmt;
342 struct lwp *l;
343 {
344 int err, error = 0;
345 struct atm_flowmap fmap;
346 struct afm_head *head;
347
348 for (head = afhead_chain.lh_first; head != NULL;
349 head = head->afh_chain.le_next) {
350
351 /* call interface to clean up maps */
352 #if defined(__NetBSD__) || defined(__OpenBSD__)
353 sprintf(fmap.af_ifname, "%s", head->afh_ifp->if_xname);
354 #else
355 sprintf(fmap.af_ifname, "%s%d",
356 head->afh_ifp->if_name, head->afh_ifp->if_unit);
357 #endif
358 err = afmioctl(dev, AFM_CLEANFMAP, (caddr_t)&fmap, flag, l);
359 if (err && error == 0)
360 error = err;
361 }
362
363 return error;
364 }
365
366 int
367 afmioctl(dev, cmd, addr, flag, l)
368 dev_t dev;
369 ioctlcmd_t cmd;
370 caddr_t addr;
371 int flag;
372 struct lwp *l;
373 {
374 int error = 0;
375 struct atm_flowmap *flowmap;
376 struct ifnet *ifp;
377
378 /* check cmd for superuser only */
379 switch (cmd) {
380 case AFM_GETFMAP:
381 break;
382 default:
383 #if (__FreeBSD_version > 400000)
384 error = suser(p);
385 #else
386 error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
387 &l->l_acflag);
388 #endif
389 if (error)
390 return (error);
391 break;
392 }
393
394 /* lookup interface */
395 flowmap = (struct atm_flowmap *)addr;
396 flowmap->af_ifname[IFNAMSIZ-1] = '\0';
397 ifp = ifunit(flowmap->af_ifname);
398 if (ifp == NULL || ifp->if_ioctl == NULL ||
399 (ifp->if_flags & IFF_RUNNING) == 0)
400 error = ENXIO;
401 else
402 error = ifp->if_ioctl(ifp, cmd, addr);
403
404 return error;
405 }
406