if_hatm_ioctl.c revision 148887
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 148887 2005-08-09 10:20:02Z rwatson $"); 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 <dev/pci/pcireg.h> 71#include <dev/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->ifp->if_drv_flags & IFF_DRV_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 hatm_load_vc(sc, cid, 0); 163 164 /* don't free below */ 165 vcc = NULL; 166 sc->open_vccs++; 167 168 done: 169 mtx_unlock(&sc->mtx); 170 if (vcc != NULL) 171 uma_zfree(sc->vcc_zone, vcc); 172 return (error); 173} 174 175void 176hatm_load_vc(struct hatm_softc *sc, u_int cid, int reopen) 177{ 178 struct hevcc *vcc = sc->vccs[cid]; 179 180 if (!(vcc->param.flags & ATMIO_FLAG_NOTX)) 181 hatm_tx_vcc_open(sc, cid); 182 if (!(vcc->param.flags & ATMIO_FLAG_NORX)) 183 hatm_rx_vcc_open(sc, cid); 184 185 if (reopen) 186 return; 187 188 /* inform management about non-NG and NG-PVCs */ 189 if (!(vcc->param.flags & ATMIO_FLAG_NG) || 190 (vcc->param.flags & ATMIO_FLAG_PVC)) 191 ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), vcc->param.vpi, 192 vcc->param.vci, 1); 193} 194 195/* 196 * VCC has been finally closed. 197 */ 198void 199hatm_vcc_closed(struct hatm_softc *sc, u_int cid) 200{ 201 struct hevcc *vcc = sc->vccs[cid]; 202 203 /* inform management about non-NG and NG-PVCs */ 204 if (!(vcc->param.flags & ATMIO_FLAG_NG) || 205 (vcc->param.flags & ATMIO_FLAG_PVC)) 206 ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), HE_VPI(cid), HE_VCI(cid), 0); 207 208 sc->open_vccs--; 209 uma_zfree(sc->vcc_zone, vcc); 210 sc->vccs[cid] = NULL; 211} 212 213/* 214 * Try to close the given VCC 215 */ 216static int 217hatm_close_vcc(struct hatm_softc *sc, struct atmio_closevcc *arg) 218{ 219 u_int cid; 220 struct hevcc *vcc; 221 int error = 0; 222 223 DBG(sc, VCC, ("Close VCC: %u.%u", arg->vpi, arg->vci)); 224 225 if((arg->vpi & ~HE_VPI_MASK) || 226 (arg->vci & ~HE_VCI_MASK) || 227 (arg->vci == 0)) 228 return (EINVAL); 229 cid = HE_CID(arg->vpi, arg->vci); 230 231 mtx_lock(&sc->mtx); 232 vcc = sc->vccs[cid]; 233 if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { 234 error = EIO; 235 goto done; 236 } 237 238 if (vcc == NULL || !(vcc->vflags & HE_VCC_OPEN)) { 239 error = ENOENT; 240 goto done; 241 } 242 243 if (vcc->vflags & HE_VCC_TX_OPEN) 244 hatm_tx_vcc_close(sc, cid); 245 if (vcc->vflags & HE_VCC_RX_OPEN) 246 hatm_rx_vcc_close(sc, cid); 247 248 if (vcc->param.flags & ATMIO_FLAG_ASYNC) 249 goto done; 250 251 while ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) && 252 (vcc->vflags & (HE_VCC_TX_CLOSING | HE_VCC_RX_CLOSING))) 253 cv_wait(&sc->vcc_cv, &sc->mtx); 254 255 if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { 256 error = EIO; 257 goto done; 258 } 259 260 if (!(vcc->vflags & ATMIO_FLAG_NOTX)) 261 hatm_tx_vcc_closed(sc, cid); 262 263 hatm_vcc_closed(sc, cid); 264 265 done: 266 mtx_unlock(&sc->mtx); 267 return (error); 268} 269 270/* 271 * IOCTL handler 272 */ 273int 274hatm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 275{ 276 struct ifreq *ifr = (struct ifreq *)data; 277 struct ifaddr *ifa = (struct ifaddr *)data; 278 struct hatm_softc *sc = ifp->if_softc; 279 struct atmio_vcctable *vtab; 280 int error = 0; 281 282 switch (cmd) { 283 284 case SIOCSIFADDR: 285 mtx_lock(&sc->mtx); 286 ifp->if_flags |= IFF_UP; 287 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 288 hatm_initialize(sc); 289 switch (ifa->ifa_addr->sa_family) { 290 291#ifdef INET 292 case AF_INET: 293 case AF_INET6: 294 ifa->ifa_rtrequest = atm_rtrequest; 295 break; 296#endif 297 default: 298 break; 299 } 300 mtx_unlock(&sc->mtx); 301 break; 302 303 case SIOCSIFFLAGS: 304 mtx_lock(&sc->mtx); 305 if (ifp->if_flags & IFF_UP) { 306 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 307 hatm_initialize(sc); 308 } 309 } else { 310 if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 311 hatm_stop(sc); 312 } 313 } 314 mtx_unlock(&sc->mtx); 315 break; 316 317 case SIOCGIFMEDIA: 318 case SIOCSIFMEDIA: 319 error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); 320 break; 321 322 case SIOCSIFMTU: 323 /* 324 * Set the interface MTU. 325 */ 326 if (ifr->ifr_mtu > ATMMTU) 327 error = EINVAL; 328 else 329 ifp->if_mtu = ifr->ifr_mtu; 330 break; 331 332 case SIOCATMGVCCS: 333 /* return vcc table */ 334 vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 335 HE_MAX_VCCS, sc->open_vccs, &sc->mtx, 1); 336 error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) + 337 vtab->count * sizeof(vtab->vccs[0])); 338 free(vtab, M_DEVBUF); 339 break; 340 341 case SIOCATMGETVCCS: /* netgraph internal use */ 342 vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 343 HE_MAX_VCCS, sc->open_vccs, &sc->mtx, 0); 344 if (vtab == NULL) { 345 error = ENOMEM; 346 break; 347 } 348 *(void **)data = vtab; 349 break; 350 351 case SIOCATMOPENVCC: /* kernel internal use */ 352 error = hatm_open_vcc(sc, (struct atmio_openvcc *)data); 353 break; 354 355 case SIOCATMCLOSEVCC: /* kernel internal use */ 356 error = hatm_close_vcc(sc, (struct atmio_closevcc *)data); 357 break; 358 359 default: 360 DBG(sc, IOCTL, ("cmd=%08lx arg=%p", cmd, data)); 361 error = EINVAL; 362 break; 363 } 364 365 return (error); 366} 367 368static int 369hatm_sysctl_natm_traffic(SYSCTL_HANDLER_ARGS) 370{ 371 int error; 372 int tmp; 373 374 tmp = hatm_natm_traffic; 375 error = sysctl_handle_int(oidp, &tmp, 0, req); 376 if (error != 0 || req->newptr == NULL) 377 return (error); 378 379 if (tmp != ATMIO_TRAFFIC_UBR && tmp != ATMIO_TRAFFIC_CBR) 380 return (EINVAL); 381 382 hatm_natm_traffic = tmp; 383 return (0); 384} 385