if_hatm_ioctl.c revision 332288
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: stable/11/sys/dev/hatm/if_hatm_ioctl.c 332288 2018-04-08 16:54:07Z brooks $"); 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_var.h> 61#include <net/if_media.h> 62#include <net/if_atm.h> 63#include <net/route.h> 64#include <netinet/in.h> 65#include <netinet/if_atm.h> 66 67#include <machine/bus.h> 68#include <machine/resource.h> 69#include <sys/bus.h> 70#include <sys/rman.h> 71#include <dev/pci/pcireg.h> 72#include <dev/pci/pcivar.h> 73 74#include <dev/utopia/utopia.h> 75#include <dev/hatm/if_hatmconf.h> 76#include <dev/hatm/if_hatmreg.h> 77#include <dev/hatm/if_hatmvar.h> 78 79static u_int hatm_natm_traffic = ATMIO_TRAFFIC_UBR; 80static u_int hatm_natm_pcr = 0; 81 82static int hatm_sysctl_natm_traffic(SYSCTL_HANDLER_ARGS); 83 84SYSCTL_DECL(_hw_atm); 85 86SYSCTL_PROC(_hw_atm, OID_AUTO, natm_traffic, CTLTYPE_UINT | CTLFLAG_RW, 87 &hatm_natm_traffic, sizeof(hatm_natm_traffic), hatm_sysctl_natm_traffic, 88 "IU", "traffic type for NATM connections"); 89SYSCTL_UINT(_hw_atm, OID_AUTO, natm_pcr, CTLFLAG_RW, 90 &hatm_natm_pcr, 0, "PCR for NATM connections"); 91 92/* 93 * Try to open the given VCC. 94 */ 95static int 96hatm_open_vcc(struct hatm_softc *sc, struct atmio_openvcc *arg) 97{ 98 u_int cid; 99 struct hevcc *vcc; 100 int error = 0; 101 102 DBG(sc, VCC, ("Open VCC: %u.%u flags=%#x", arg->param.vpi, 103 arg->param.vci, arg->param.flags)); 104 105 if ((arg->param.vpi & ~HE_VPI_MASK) || 106 (arg->param.vci & ~HE_VCI_MASK) || 107 (arg->param.vci == 0)) 108 return (EINVAL); 109 cid = HE_CID(arg->param.vpi, arg->param.vci); 110 111 if ((arg->param.flags & ATMIO_FLAG_NOTX) && 112 (arg->param.flags & ATMIO_FLAG_NORX)) 113 return (EINVAL); 114 115 vcc = uma_zalloc(sc->vcc_zone, M_NOWAIT | M_ZERO); 116 if (vcc == NULL) 117 return (ENOMEM); 118 119 mtx_lock(&sc->mtx); 120 if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { 121 error = EIO; 122 goto done; 123 } 124 if (sc->vccs[cid] != NULL) { 125 error = EBUSY; 126 goto done; 127 } 128 vcc->param = arg->param; 129 vcc->rxhand = arg->rxhand; 130 switch (vcc->param.aal) { 131 132 case ATMIO_AAL_0: 133 case ATMIO_AAL_5: 134 case ATMIO_AAL_RAW: 135 break; 136 137 default: 138 error = EINVAL; 139 goto done; 140 } 141 switch (vcc->param.traffic) { 142 143 case ATMIO_TRAFFIC_UBR: 144 case ATMIO_TRAFFIC_CBR: 145 case ATMIO_TRAFFIC_ABR: 146 break; 147 148 default: 149 error = EINVAL; 150 goto done; 151 } 152 vcc->ntpds = 0; 153 vcc->chain = vcc->last = NULL; 154 vcc->ibytes = vcc->ipackets = 0; 155 vcc->obytes = vcc->opackets = 0; 156 157 if (!(vcc->param.flags & ATMIO_FLAG_NOTX) && 158 (error = hatm_tx_vcc_can_open(sc, cid, vcc)) != 0) 159 goto done; 160 161 /* ok - go ahead */ 162 sc->vccs[cid] = vcc; 163 hatm_load_vc(sc, cid, 0); 164 165 /* don't free below */ 166 vcc = NULL; 167 sc->open_vccs++; 168 169 done: 170 mtx_unlock(&sc->mtx); 171 if (vcc != NULL) 172 uma_zfree(sc->vcc_zone, vcc); 173 return (error); 174} 175 176void 177hatm_load_vc(struct hatm_softc *sc, u_int cid, int reopen) 178{ 179 struct hevcc *vcc = sc->vccs[cid]; 180 181 if (!(vcc->param.flags & ATMIO_FLAG_NOTX)) 182 hatm_tx_vcc_open(sc, cid); 183 if (!(vcc->param.flags & ATMIO_FLAG_NORX)) 184 hatm_rx_vcc_open(sc, cid); 185 186 if (reopen) 187 return; 188 189 /* inform management about non-NG and NG-PVCs */ 190 if (!(vcc->param.flags & ATMIO_FLAG_NG) || 191 (vcc->param.flags & ATMIO_FLAG_PVC)) 192 ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), vcc->param.vpi, 193 vcc->param.vci, 1); 194} 195 196/* 197 * VCC has been finally closed. 198 */ 199void 200hatm_vcc_closed(struct hatm_softc *sc, u_int cid) 201{ 202 struct hevcc *vcc = sc->vccs[cid]; 203 204 /* inform management about non-NG and NG-PVCs */ 205 if (!(vcc->param.flags & ATMIO_FLAG_NG) || 206 (vcc->param.flags & ATMIO_FLAG_PVC)) 207 ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), HE_VPI(cid), HE_VCI(cid), 0); 208 209 sc->open_vccs--; 210 uma_zfree(sc->vcc_zone, vcc); 211 sc->vccs[cid] = NULL; 212} 213 214/* 215 * Try to close the given VCC 216 */ 217static int 218hatm_close_vcc(struct hatm_softc *sc, struct atmio_closevcc *arg) 219{ 220 u_int cid; 221 struct hevcc *vcc; 222 int error = 0; 223 224 DBG(sc, VCC, ("Close VCC: %u.%u", arg->vpi, arg->vci)); 225 226 if((arg->vpi & ~HE_VPI_MASK) || 227 (arg->vci & ~HE_VCI_MASK) || 228 (arg->vci == 0)) 229 return (EINVAL); 230 cid = HE_CID(arg->vpi, arg->vci); 231 232 mtx_lock(&sc->mtx); 233 vcc = sc->vccs[cid]; 234 if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { 235 error = EIO; 236 goto done; 237 } 238 239 if (vcc == NULL || !(vcc->vflags & HE_VCC_OPEN)) { 240 error = ENOENT; 241 goto done; 242 } 243 244 if (vcc->vflags & HE_VCC_TX_OPEN) 245 hatm_tx_vcc_close(sc, cid); 246 if (vcc->vflags & HE_VCC_RX_OPEN) 247 hatm_rx_vcc_close(sc, cid); 248 249 if (vcc->param.flags & ATMIO_FLAG_ASYNC) 250 goto done; 251 252 while ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) && 253 (vcc->vflags & (HE_VCC_TX_CLOSING | HE_VCC_RX_CLOSING))) 254 cv_wait(&sc->vcc_cv, &sc->mtx); 255 256 if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { 257 error = EIO; 258 goto done; 259 } 260 261 if (!(vcc->vflags & ATMIO_FLAG_NOTX)) 262 hatm_tx_vcc_closed(sc, cid); 263 264 hatm_vcc_closed(sc, cid); 265 266 done: 267 mtx_unlock(&sc->mtx); 268 return (error); 269} 270 271/* 272 * IOCTL handler 273 */ 274int 275hatm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 276{ 277 struct ifreq *ifr = (struct ifreq *)data; 278 struct ifaddr *ifa = (struct ifaddr *)data; 279 struct hatm_softc *sc = ifp->if_softc; 280 struct atmio_vcctable *vtab; 281 int error = 0; 282 283 switch (cmd) { 284 285 case SIOCSIFADDR: 286 mtx_lock(&sc->mtx); 287 ifp->if_flags |= IFF_UP; 288 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 289 hatm_initialize(sc); 290 switch (ifa->ifa_addr->sa_family) { 291 292#ifdef INET 293 case AF_INET: 294 case AF_INET6: 295 ifa->ifa_rtrequest = atm_rtrequest; 296 break; 297#endif 298 default: 299 break; 300 } 301 mtx_unlock(&sc->mtx); 302 break; 303 304 case SIOCSIFFLAGS: 305 mtx_lock(&sc->mtx); 306 if (ifp->if_flags & IFF_UP) { 307 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 308 hatm_initialize(sc); 309 } 310 } else { 311 if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 312 hatm_stop(sc); 313 } 314 } 315 mtx_unlock(&sc->mtx); 316 break; 317 318 case SIOCGIFMEDIA: 319 case SIOCSIFMEDIA: 320 error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); 321 break; 322 323 case SIOCSIFMTU: 324 /* 325 * Set the interface MTU. 326 */ 327 if (ifr->ifr_mtu > ATMMTU) 328 error = EINVAL; 329 else 330 ifp->if_mtu = ifr->ifr_mtu; 331 break; 332 333 case SIOCATMGVCCS: 334 /* return vcc table */ 335 vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 336 HE_MAX_VCCS, sc->open_vccs, &sc->mtx, 1); 337 error = copyout(vtab, ifr_data_get_ptr(ifr), sizeof(*vtab) + 338 vtab->count * sizeof(vtab->vccs[0])); 339 free(vtab, M_DEVBUF); 340 break; 341 342 case SIOCATMGETVCCS: /* netgraph internal use */ 343 vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 344 HE_MAX_VCCS, sc->open_vccs, &sc->mtx, 0); 345 if (vtab == NULL) { 346 error = ENOMEM; 347 break; 348 } 349 *(void **)data = vtab; 350 break; 351 352 case SIOCATMOPENVCC: /* kernel internal use */ 353 error = hatm_open_vcc(sc, (struct atmio_openvcc *)data); 354 break; 355 356 case SIOCATMCLOSEVCC: /* kernel internal use */ 357 error = hatm_close_vcc(sc, (struct atmio_closevcc *)data); 358 break; 359 360 default: 361 DBG(sc, IOCTL, ("cmd=%08lx arg=%p", cmd, data)); 362 error = EINVAL; 363 break; 364 } 365 366 return (error); 367} 368 369static int 370hatm_sysctl_natm_traffic(SYSCTL_HANDLER_ARGS) 371{ 372 int error; 373 int tmp; 374 375 tmp = hatm_natm_traffic; 376 error = sysctl_handle_int(oidp, &tmp, 0, req); 377 if (error != 0 || req->newptr == NULL) 378 return (error); 379 380 if (tmp != ATMIO_TRAFFIC_UBR && tmp != ATMIO_TRAFFIC_CBR) 381 return (EINVAL); 382 383 hatm_natm_traffic = tmp; 384 return (0); 385} 386