Home | History | Annotate | Line # | Download | only in altq
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