]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/hatm/if_hatm_ioctl.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / hatm / if_hatm_ioctl.c
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$");
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
78 static u_int hatm_natm_traffic = ATMIO_TRAFFIC_UBR;
79 static u_int hatm_natm_pcr = 0;
80
81 static int hatm_sysctl_natm_traffic(SYSCTL_HANDLER_ARGS);
82
83 SYSCTL_DECL(_hw_atm);
84
85 SYSCTL_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");
88 SYSCTL_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  */
94 static int
95 hatm_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
175 void
176 hatm_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  */
198 void
199 hatm_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  */
216 static int
217 hatm_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  */
273 int
274 hatm_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
368 static int
369 hatm_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 }