1 /* $NetBSD: altq_afmap.c,v 1.19 2008/11/07 00:20:01 dyoung Exp $ */ 2 /* $KAME: altq_afmap.c,v 1.12 2005/04/13 03:44:24 suz Exp $ */ 3 4 /* 5 * Copyright (C) 1997-2002 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.19 2008/11/07 00:20:01 dyoung Exp $"); 40 41 #ifdef _KERNEL_OPT 42 #include "opt_altq.h" 43 #include "opt_inet.h" 44 #endif 45 46 #ifdef ALTQ_AFMAP 47 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 #include <sys/kauth.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 #ifdef ALTQ3_COMPAT 69 70 LIST_HEAD(, afm_head) afhead_chain; 71 72 static struct afm *afm_match4(struct afm_head *, struct flowinfo_in *); 73 #ifdef INET6 74 static struct afm *afm_match6(struct afm_head *, struct flowinfo_in6 *); 75 #endif 76 77 /* 78 * rules to block interrupts: afm_match can be called from a net 79 * level interrupt so that other routines handling the lists should 80 * be called in splnet(). 81 */ 82 int 83 afm_alloc(struct ifnet *ifp) 84 { 85 struct afm_head *head; 86 87 head = malloc(sizeof(struct afm_head), M_DEVBUF, M_WAITOK|M_ZERO); 88 if (head == NULL) 89 panic("afm_alloc: malloc failed!"); 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(struct ifnet *ifp) 104 { 105 struct afm_head *head; 106 107 for (head = afhead_chain.lh_first; head != NULL; 108 head = head->afh_chain.le_next) 109 if (head->afh_ifp == ifp) 110 break; 111 if (head == NULL) 112 return (-1); 113 114 afm_removeall(ifp); 115 116 LIST_REMOVE(head, afh_chain); 117 118 free(head, M_DEVBUF); 119 return 0; 120 } 121 122 struct afm * 123 afm_top(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 138 afm_add(struct ifnet *ifp, struct atm_flowmap *flowmap) 139 { 140 struct afm_head *head; 141 struct afm *afm; 142 143 for (head = afhead_chain.lh_first; head != NULL; 144 head = head->afh_chain.le_next) 145 if (head->afh_ifp == ifp) 146 break; 147 if (head == NULL) 148 return (-1); 149 150 if (flowmap->af_flowinfo.fi_family == AF_INET) { 151 if (flowmap->af_flowinfo.fi_len != sizeof(struct flowinfo_in)) 152 return (EINVAL); 153 #ifdef INET6 154 } else if (flowmap->af_flowinfo.fi_family == AF_INET6) { 155 if (flowmap->af_flowinfo.fi_len != sizeof(struct flowinfo_in6)) 156 return (EINVAL); 157 #endif 158 } else 159 return (EINVAL); 160 161 afm = malloc(sizeof(struct afm), M_DEVBUF, M_WAITOK|M_ZERO); 162 if (afm == NULL) 163 return (ENOMEM); 164 165 afm->afm_vci = flowmap->af_vci; 166 afm->afm_vpi = flowmap->af_vpi; 167 (void)memcpy(&afm->afm_flowinfo, &flowmap->af_flowinfo, 168 flowmap->af_flowinfo.fi_len); 169 170 LIST_INSERT_HEAD(&head->afh_head, afm, afm_list); 171 return 0; 172 } 173 174 int 175 afm_remove(struct afm *afm) 176 { 177 LIST_REMOVE(afm, afm_list); 178 free(afm, M_DEVBUF); 179 return (0); 180 } 181 182 int 183 afm_removeall(struct ifnet *ifp) 184 { 185 struct afm_head *head; 186 struct afm *afm; 187 188 for (head = afhead_chain.lh_first; head != NULL; 189 head = head->afh_chain.le_next) 190 if (head->afh_ifp == ifp) 191 break; 192 if (head == NULL) 193 return (-1); 194 195 while ((afm = head->afh_head.lh_first) != NULL) 196 afm_remove(afm); 197 return (0); 198 } 199 200 struct afm * 201 afm_lookup(struct ifnet *ifp, int vpi, int vci) 202 { 203 struct afm_head *head; 204 struct afm *afm; 205 206 for (head = afhead_chain.lh_first; head != NULL; 207 head = head->afh_chain.le_next) 208 if (head->afh_ifp == ifp) 209 break; 210 if (head == NULL) 211 return NULL; 212 213 for (afm = head->afh_head.lh_first; afm != NULL; 214 afm = afm->afm_list.le_next) 215 if (afm->afm_vpi == vpi && afm->afm_vci == vci) 216 break; 217 return afm; 218 } 219 220 static struct afm * 221 afm_match4(struct afm_head *head, struct flowinfo_in *fp) 222 { 223 struct afm *afm; 224 225 for (afm = head->afh_head.lh_first; afm != NULL; 226 afm = afm->afm_list.le_next) { 227 if (afm->afm_flowinfo4.fi_dst.s_addr != 0 && 228 afm->afm_flowinfo4.fi_dst.s_addr != fp->fi_dst.s_addr) 229 continue; 230 if (afm->afm_flowinfo4.fi_dport != 0 && 231 afm->afm_flowinfo4.fi_dport != fp->fi_dport) 232 continue; 233 if (afm->afm_flowinfo4.fi_src.s_addr != 0 && 234 afm->afm_flowinfo4.fi_src.s_addr != fp->fi_src.s_addr) 235 continue; 236 if (afm->afm_flowinfo4.fi_sport != 0 && 237 afm->afm_flowinfo4.fi_sport != fp->fi_sport) 238 continue; 239 if (afm->afm_flowinfo4.fi_proto != 0 && 240 afm->afm_flowinfo4.fi_proto != fp->fi_proto) 241 continue; 242 /* match found! */ 243 return (afm); 244 } 245 return NULL; 246 } 247 248 #ifdef INET6 249 static struct afm * 250 afm_match6(struct afm_head *head, struct flowinfo_in6 *fp) 251 { 252 struct afm *afm; 253 254 for (afm = head->afh_head.lh_first; afm != NULL; 255 afm = afm->afm_list.le_next) { 256 if (afm->afm_flowinfo6.fi6_flowlabel != 0 && 257 afm->afm_flowinfo6.fi6_flowlabel != fp->fi6_flowlabel) 258 continue; 259 #ifdef notyet 260 if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi6_dst) && 261 !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi6_dst, 262 &fp->fi6_dst)) 263 continue; 264 if (afm->afm_flowinfo6.fi6_dport != 0 && 265 afm->afm_flowinfo6.fi6_dport != fp->fi6_dport) 266 continue; 267 #endif 268 if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi6_src) && 269 !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi6_src, 270 &fp->fi6_src)) 271 continue; 272 #ifdef notyet 273 if (afm->afm_flowinfo6.fi6_sport != 0 && 274 afm->afm_flowinfo6.fi6_sport != fp->fi6_sport) 275 continue; 276 #endif 277 if (afm->afm_flowinfo6.fi6_proto != 0 && 278 afm->afm_flowinfo6.fi6_proto != fp->fi6_proto) 279 continue; 280 /* match found! */ 281 return (afm); 282 } 283 return NULL; 284 } 285 #endif 286 287 /* should be called in splnet() */ 288 struct afm * 289 afm_match(struct ifnet *ifp, struct flowinfo *flow) 290 { 291 struct afm_head *head; 292 293 for (head = afhead_chain.lh_first; head != NULL; 294 head = head->afh_chain.le_next) 295 if (head->afh_ifp == ifp) 296 break; 297 if (head == NULL) 298 return NULL; 299 300 switch (flow->fi_family) { 301 case AF_INET: 302 return (afm_match4(head, (struct flowinfo_in *)flow)); 303 304 #ifdef INET6 305 case AF_INET6: 306 return (afm_match6(head, (struct flowinfo_in6 *)flow)); 307 #endif 308 309 default: 310 return NULL; 311 } 312 } 313 314 /* 315 * afm device interface 316 */ 317 altqdev_decl(afm); 318 319 int 320 afmopen(dev_t dev, int flag, int fmt, 321 struct lwp *l) 322 { 323 return 0; 324 } 325 326 int 327 afmclose(dev_t dev, int flag, int fmt, struct lwp *l) 328 { 329 int err, error = 0; 330 struct atm_flowmap fmap; 331 struct afm_head *head; 332 333 for (head = afhead_chain.lh_first; head != NULL; 334 head = head->afh_chain.le_next) { 335 336 /* call interface to clean up maps */ 337 sprintf(fmap.af_ifname, "%s", head->afh_ifp->if_xname); 338 err = afmioctl(dev, AFM_CLEANFMAP, (void *)&fmap, flag, l); 339 if (err && error == 0) 340 error = err; 341 } 342 343 return error; 344 } 345 346 int 347 afmioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag, 348 struct lwp *l) 349 { 350 int error = 0; 351 struct atm_flowmap *flowmap; 352 struct ifnet *ifp; 353 354 /* check cmd for superuser only */ 355 switch (cmd) { 356 case AFM_GETFMAP: 357 break; 358 default: 359 #if (__FreeBSD_version > 400000) 360 error = suser(p); 361 #else 362 error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_ALTQ, 363 KAUTH_REQ_NETWORK_ALTQ_AFMAP, NULL, NULL, NULL); 364 #endif 365 if (error) 366 return (error); 367 break; 368 } 369 370 /* lookup interface */ 371 flowmap = (struct atm_flowmap *)addr; 372 flowmap->af_ifname[IFNAMSIZ-1] = '\0'; 373 ifp = ifunit(flowmap->af_ifname); 374 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) 375 error = ENXIO; 376 else 377 error = ifp->if_ioctl(ifp, cmd, addr); 378 379 return error; 380 } 381 382 #endif /* ALTQ3_COMPAT */ 383 #endif /* ALTQ_AFMAP */ 384