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