if_hatm_ioctl.c revision 118205
1/* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * Author: Hartmut Brandt <harti@freebsd.org> 28 * 29 * ForeHE driver. 30 * 31 * Ioctl handler. 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: head/sys/dev/hatm/if_hatm_ioctl.c 118205 2003-07-30 11:32:42Z harti $"); 36 37#include "opt_inet.h" 38#include "opt_natm.h" 39 40#include <sys/types.h> 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/malloc.h> 44#include <sys/kernel.h> 45#include <sys/bus.h> 46#include <sys/errno.h> 47#include <sys/conf.h> 48#include <sys/module.h> 49#include <sys/queue.h> 50#include <sys/syslog.h> 51#include <sys/condvar.h> 52#include <sys/sysctl.h> 53#include <vm/uma.h> 54 55#include <sys/sockio.h> 56#include <sys/mbuf.h> 57#include <sys/socket.h> 58 59#include <net/if.h> 60#include <net/if_media.h> 61#include <net/if_atm.h> 62#include <net/route.h> 63#include <netinet/in.h> 64#include <netinet/if_atm.h> 65 66#include <machine/bus.h> 67#include <machine/resource.h> 68#include <sys/bus.h> 69#include <sys/rman.h> 70#include <pci/pcireg.h> 71#include <pci/pcivar.h> 72 73#include <dev/utopia/utopia.h> 74#include <dev/hatm/if_hatmconf.h> 75#include <dev/hatm/if_hatmreg.h> 76#include <dev/hatm/if_hatmvar.h> 77 78static u_int hatm_natm_traffic = ATMIO_TRAFFIC_UBR; 79static u_int hatm_natm_pcr = 0; 80 81static int hatm_sysctl_natm_traffic(SYSCTL_HANDLER_ARGS); 82 83SYSCTL_DECL(_hw_atm); 84 85SYSCTL_PROC(_hw_atm, OID_AUTO, natm_traffic, CTLTYPE_UINT | CTLFLAG_RW, 86 &hatm_natm_traffic, sizeof(hatm_natm_traffic), hatm_sysctl_natm_traffic, 87 "IU", "traffic type for NATM connections"); 88SYSCTL_UINT(_hw_atm, OID_AUTO, natm_pcr, CTLFLAG_RW, 89 &hatm_natm_pcr, 0, "PCR for NATM connections"); 90 91/* 92 * Try to open the given VCC. 93 */ 94static int 95hatm_open_vcc(struct hatm_softc *sc, struct atmio_openvcc *arg) 96{ 97 u_int cid; 98 struct hevcc *vcc; 99 int error = 0; 100 101 DBG(sc, VCC, ("Open VCC: %u.%u flags=%#x", arg->param.vpi, 102 arg->param.vci, arg->param.flags)); 103 104 if ((arg->param.vpi & ~HE_VPI_MASK) || 105 (arg->param.vci & ~HE_VCI_MASK) || 106 (arg->param.vci == 0)) 107 return (EINVAL); 108 cid = HE_CID(arg->param.vpi, arg->param.vci); 109 110 if ((arg->param.flags & ATMIO_FLAG_NOTX) && 111 (arg->param.flags & ATMIO_FLAG_NORX)) 112 return (EINVAL); 113 114 vcc = uma_zalloc(sc->vcc_zone, M_NOWAIT | M_ZERO); 115 if (vcc == NULL) 116 return (ENOMEM); 117 118 mtx_lock(&sc->mtx); 119 if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) { 120 error = EIO; 121 goto done; 122 } 123 if (sc->vccs[cid] != NULL) { 124 error = EBUSY; 125 goto done; 126 } 127 vcc->param = arg->param; 128 vcc->rxhand = arg->rxhand; 129 switch (vcc->param.aal) { 130 131 case ATMIO_AAL_0: 132 case ATMIO_AAL_5: 133 case ATMIO_AAL_RAW: 134 break; 135 136 default: 137 error = EINVAL; 138 goto done; 139 } 140 switch (vcc->param.traffic) { 141 142 case ATMIO_TRAFFIC_UBR: 143 case ATMIO_TRAFFIC_CBR: 144 case ATMIO_TRAFFIC_ABR: 145 break; 146 147 default: 148 error = EINVAL; 149 goto done; 150 } 151 vcc->ntpds = 0; 152 vcc->chain = vcc->last = NULL; 153 vcc->ibytes = vcc->ipackets = 0; 154 vcc->obytes = vcc->opackets = 0; 155 156 if (!(vcc->param.flags & ATMIO_FLAG_NOTX) && 157 (error = hatm_tx_vcc_can_open(sc, cid, vcc)) != 0) 158 goto done; 159 160 /* ok - go ahead */ 161 sc->vccs[cid] = vcc; 162 163 if (!(vcc->param.flags & ATMIO_FLAG_NOTX)) 164 hatm_tx_vcc_open(sc, cid); 165 if (!(vcc->param.flags & ATMIO_FLAG_NORX)) 166 hatm_rx_vcc_open(sc, cid); 167 168 /* inform management about non-NG and NG-PVCs */ 169 if (!(vcc->param.flags & ATMIO_FLAG_NG) || 170 (vcc->param.flags & ATMIO_FLAG_PVC)) 171 ATMEV_SEND_VCC_CHANGED(&sc->ifatm, arg->param.vpi, 172 arg->param.vci, 1); 173 174 /* don't free below */ 175 vcc = NULL; 176 177 sc->open_vccs++; 178 179 done: 180 mtx_unlock(&sc->mtx); 181 if (vcc != NULL) 182 uma_zfree(sc->vcc_zone, vcc); 183 return (error); 184} 185 186/* 187 * Enable ioctl for NATM. Map to an open ioctl. 188 */ 189static int 190hatm_open_vcc1(struct hatm_softc *sc, struct atm_pseudoioctl *ph) 191{ 192 struct atmio_openvcc *v; 193 int error; 194 195 if ((v = malloc(sizeof(*v), M_TEMP, M_NOWAIT | M_ZERO)) == NULL) 196 return (ENOMEM); 197 198 v->param.flags = ATM_PH_FLAGS(&ph->aph) & 199 (ATM_PH_AAL5 | ATM_PH_LLCSNAP); 200 v->param.vpi = ATM_PH_VPI(&ph->aph); 201 v->param.vci = ATM_PH_VCI(&ph->aph); 202 v->param.aal = (ATM_PH_FLAGS(&ph->aph) & ATM_PH_AAL5) 203 ? ATMIO_AAL_5 : ATMIO_AAL_0; 204 v->param.traffic = hatm_natm_traffic; 205 v->rxhand = ph->rxhand; 206 if ((v->param.tparam.pcr = hatm_natm_pcr) == 0 || 207 hatm_natm_pcr > sc->ifatm.mib.pcr) 208 v->param.tparam.pcr = sc->ifatm.mib.pcr; 209 v->param.tparam.mcr = 0; 210 211 error = hatm_open_vcc(sc, v); 212 if (error == 0) 213 sc->vccs[HE_CID(v->param.vpi, v->param.vci)]->vflags |= 214 HE_VCC_ASYNC; 215 216 free(v, M_TEMP); 217 218 return (error); 219} 220 221/* 222 * VCC has been finally closed. 223 */ 224void 225hatm_vcc_closed(struct hatm_softc *sc, u_int cid) 226{ 227 struct hevcc *vcc = sc->vccs[cid]; 228 229 /* inform management about non-NG and NG-PVCs */ 230 if (!(vcc->param.flags & ATMIO_FLAG_NG) || 231 (vcc->param.flags & ATMIO_FLAG_PVC)) 232 ATMEV_SEND_VCC_CHANGED(&sc->ifatm, HE_VPI(cid), HE_VCI(cid), 0); 233 234 sc->open_vccs--; 235 uma_zfree(sc->vcc_zone, vcc); 236 sc->vccs[cid] = NULL; 237} 238 239/* 240 * Try to close the given VCC 241 */ 242static int 243hatm_close_vcc(struct hatm_softc *sc, struct atmio_closevcc *arg) 244{ 245 u_int cid; 246 struct hevcc *vcc; 247 int error = 0; 248 249 DBG(sc, VCC, ("Close VCC: %u.%u", arg->vpi, arg->vci)); 250 251 if((arg->vpi & ~HE_VPI_MASK) || 252 (arg->vci & ~HE_VCI_MASK) || 253 (arg->vci == 0)) 254 return (EINVAL); 255 cid = HE_CID(arg->vpi, arg->vci); 256 257 mtx_lock(&sc->mtx); 258 vcc = sc->vccs[cid]; 259 if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) { 260 error = EIO; 261 goto done; 262 } 263 264 if (vcc == NULL || !(vcc->vflags & HE_VCC_OPEN)) { 265 error = ENOENT; 266 goto done; 267 } 268 269 if (vcc->vflags & HE_VCC_TX_OPEN) 270 hatm_tx_vcc_close(sc, cid); 271 if (vcc->vflags & HE_VCC_RX_OPEN) 272 hatm_rx_vcc_close(sc, cid); 273 274 if (vcc->vflags & HE_VCC_ASYNC) 275 goto done; 276 277 while ((sc->ifatm.ifnet.if_flags & IFF_RUNNING) && 278 (vcc->vflags & (HE_VCC_TX_CLOSING | HE_VCC_RX_CLOSING))) 279 cv_wait(&sc->vcc_cv, &sc->mtx); 280 281 if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) { 282 error = EIO; 283 goto done; 284 } 285 286 if (!(vcc->vflags & ATMIO_FLAG_NOTX)) 287 hatm_tx_vcc_closed(sc, cid); 288 289 hatm_vcc_closed(sc, cid); 290 291 done: 292 mtx_unlock(&sc->mtx); 293 return (error); 294} 295 296static int 297hatm_close_vcc1(struct hatm_softc *sc, struct atm_pseudoioctl *ph) 298{ 299 struct atmio_closevcc v; 300 301 v.vpi = ATM_PH_VPI(&ph->aph); 302 v.vci = ATM_PH_VCI(&ph->aph); 303 304 return (hatm_close_vcc(sc, &v)); 305} 306 307/* 308 * IOCTL handler 309 */ 310int 311hatm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 312{ 313 struct ifreq *ifr = (struct ifreq *)data; 314 struct ifaddr *ifa = (struct ifaddr *)data; 315 struct hatm_softc *sc = (struct hatm_softc *)ifp->if_softc; 316 struct atmio_vcctable *vtab; 317 int error = 0; 318 319 switch (cmd) { 320 321 case SIOCSIFADDR: 322 mtx_lock(&sc->mtx); 323 ifp->if_flags |= IFF_UP; 324 if (!(ifp->if_flags & IFF_RUNNING)) 325 hatm_initialize(sc); 326 switch (ifa->ifa_addr->sa_family) { 327 328#ifdef INET 329 case AF_INET: 330 case AF_INET6: 331 ifa->ifa_rtrequest = atm_rtrequest; 332 break; 333#endif 334 default: 335 break; 336 } 337 mtx_unlock(&sc->mtx); 338 break; 339 340 case SIOCSIFFLAGS: 341 mtx_lock(&sc->mtx); 342 if (ifp->if_flags & IFF_UP) { 343 if (!(ifp->if_flags & IFF_RUNNING)) { 344 hatm_initialize(sc); 345 } 346 } else { 347 if (ifp->if_flags & IFF_RUNNING) { 348 hatm_stop(sc); 349 } 350 } 351 mtx_unlock(&sc->mtx); 352 break; 353 354 case SIOCGIFMEDIA: 355 case SIOCSIFMEDIA: 356 error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); 357 break; 358 359 case SIOCSIFMTU: 360 /* 361 * Set the interface MTU. 362 */ 363 if (ifr->ifr_mtu > ATMMTU) 364 error = EINVAL; 365 else 366 ifp->if_mtu = ifr->ifr_mtu; 367 break; 368 369 case SIOCATMGVCCS: 370 /* return vcc table */ 371 vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 372 HE_MAX_VCCS, sc->open_vccs, &sc->mtx, 1); 373 error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) + 374 vtab->count * sizeof(vtab->vccs[0])); 375 free(vtab, M_DEVBUF); 376 break; 377 378 case SIOCATMENA: /* NATM internal use */ 379 error = hatm_open_vcc1(sc, (struct atm_pseudoioctl *)data); 380 break; 381 382 case SIOCATMDIS: /* NATM internal use */ 383 error = hatm_close_vcc1(sc, (struct atm_pseudoioctl *)data); 384 break; 385 386 case SIOCATMGETVCCS: /* netgraph internal use */ 387 vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 388 HE_MAX_VCCS, sc->open_vccs, &sc->mtx, 0); 389 if (vtab == NULL) { 390 error = ENOMEM; 391 break; 392 } 393 *(void **)data = vtab; 394 break; 395 396 case SIOCATMOPENVCC: /* netgraph/harp internal use */ 397 error = hatm_open_vcc(sc, (struct atmio_openvcc *)data); 398 break; 399 400 case SIOCATMCLOSEVCC: /* netgraph and HARP internal use */ 401 error = hatm_close_vcc(sc, (struct atmio_closevcc *)data); 402 break; 403 404 default: 405 DBG(sc, IOCTL, ("cmd=%08lx arg=%p", cmd, data)); 406 error = EINVAL; 407 break; 408 } 409 410 return (error); 411} 412 413static int 414hatm_sysctl_natm_traffic(SYSCTL_HANDLER_ARGS) 415{ 416 int error; 417 int tmp; 418 419 tmp = hatm_natm_traffic; 420 error = sysctl_handle_int(oidp, &tmp, 0, req); 421 if (error != 0 || req->newptr == NULL) 422 return (error); 423 424 if (tmp != ATMIO_TRAFFIC_UBR && tmp != ATMIO_TRAFFIC_CBR) 425 return (EINVAL); 426 427 hatm_natm_traffic = tmp; 428 return (0); 429} 430