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