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