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