1 /*        $NetBSD: altq_conf.c,v 1.23 2025/01/08 13:00:04 joe Exp $   */
2 /*        $KAME: altq_conf.c,v 1.24 2005/04/13 03:44:24 suz Exp $     */
3 
4 /*
5  * Copyright (C) 1997-2003
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 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: altq_conf.c,v 1.23 2025/01/08 13:00:04 joe Exp $");
32 
33 #ifdef _KERNEL_OPT
34 #include "opt_altq.h"
35 #include "opt_inet.h"
36 #endif
37 
38 /*
39  * altq device interface.
40  */
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/socket.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/errno.h>
47 #include <sys/kauth.h>
48 
49 #include <net/if.h>
50 
51 #include <altq/altq.h>
52 #include <altq/altqconf.h>
53 #include <altq/altq_conf.h>
54 
55 #ifdef ALTQ3_COMPAT
56 
57 #ifdef ALTQ_CBQ
58 altqdev_decl(cbq);
59 #endif
60 #ifdef ALTQ_WFQ
61 altqdev_decl(wfq);
62 #endif
63 #ifdef ALTQ_AFMAP
64 altqdev_decl(afm);
65 #endif
66 #ifdef ALTQ_FIFOQ
67 altqdev_decl(fifoq);
68 #endif
69 #ifdef ALTQ_RED
70 altqdev_decl(red);
71 #endif
72 #ifdef ALTQ_RIO
73 altqdev_decl(rio);
74 #endif
75 #ifdef ALTQ_LOCALQ
76 altqdev_decl(localq);
77 #endif
78 #ifdef ALTQ_HFSC
79 altqdev_decl(hfsc);
80 #endif
81 #ifdef ALTQ_CDNR
82 altqdev_decl(cdnr);
83 #endif
84 #ifdef ALTQ_BLUE
85 altqdev_decl(blue);
86 #endif
87 #ifdef ALTQ_PRIQ
88 altqdev_decl(priq);
89 #endif
90 #ifdef ALTQ_JOBS
91 altqdev_decl(jobs);
92 #endif
93 
94 /*
95  * altq minor device (discipline) table
96  */
97 static struct altqsw altqsw[] = {                                     /* minor */
98           {"altq", noopen,    noclose,  noioctl},  /* 0 (reserved) */
99 #ifdef ALTQ_CBQ
100           {"cbq",   cbqopen,  cbqclose, cbqioctl},          /* 1 */
101 #else
102           {"noq",   noopen,             noclose,  noioctl}, /* 1 */
103 #endif
104 #ifdef ALTQ_WFQ
105           {"wfq",   wfqopen,  wfqclose, wfqioctl},          /* 2 */
106 #else
107           {"noq",   noopen,             noclose,  noioctl}, /* 2 */
108 #endif
109 #ifdef ALTQ_AFMAP
110           {"afm",   afmopen,  afmclose, afmioctl},          /* 3 */
111 #else
112           {"noq",   noopen,             noclose,  noioctl}, /* 3 */
113 #endif
114 #ifdef ALTQ_FIFOQ
115           {"fifoq", fifoqopen,          fifoqclose,         fifoqioctl},        /* 4 */
116 #else
117           {"noq",   noopen,             noclose,  noioctl}, /* 4 */
118 #endif
119 #ifdef ALTQ_RED
120           {"red", redopen,    redclose, redioctl},          /* 5 */
121 #else
122           {"noq",   noopen,             noclose,  noioctl}, /* 5 */
123 #endif
124 #ifdef ALTQ_RIO
125           {"rio", rioopen,    rioclose, rioioctl},          /* 6 */
126 #else
127           {"noq",   noopen,             noclose,  noioctl}, /* 6 */
128 #endif
129 #ifdef ALTQ_LOCALQ
130           {"localq",localqopen,         localqclose,        localqioctl}, /* 7 (local use) */
131 #else
132           {"noq",   noopen,             noclose,  noioctl},  /* 7 (local use) */
133 #endif
134 #ifdef ALTQ_HFSC
135           {"hfsc",hfscopen,   hfscclose,          hfscioctl},         /* 8 */
136 #else
137           {"noq",   noopen,             noclose,  noioctl}, /* 8 */
138 #endif
139 #ifdef ALTQ_CDNR
140           {"cdnr",cdnropen,   cdnrclose,          cdnrioctl},         /* 9 */
141 #else
142           {"noq",   noopen,             noclose,  noioctl}, /* 9 */
143 #endif
144 #ifdef ALTQ_BLUE
145           {"blue",blueopen,   blueclose,          blueioctl},         /* 10 */
146 #else
147           {"noq",   noopen,             noclose,  noioctl}, /* 10 */
148 #endif
149 #ifdef ALTQ_PRIQ
150           {"priq",priqopen,   priqclose,          priqioctl},         /* 11 */
151 #else
152           {"noq",   noopen,             noclose,  noioctl}, /* 11 */
153 #endif
154 #ifdef ALTQ_JOBS
155           {"jobs",jobsopen,   jobsclose,          jobsioctl},         /* 12 */
156 #else
157           {"noq", noopen,               noclose,  noioctl}, /* 12 */
158 #endif
159 };
160 
161 /*
162  * altq major device support
163  */
164 int       naltqsw = sizeof (altqsw) / sizeof (altqsw[0]);
165 
166 dev_type_open(altqopen);
167 dev_type_close(altqclose);
168 dev_type_ioctl(altqioctl);
169 
170 const struct cdevsw altq_cdevsw = {
171           .d_open = altqopen,
172           .d_close = altqclose,
173           .d_read = noread,
174           .d_write = nowrite,
175           .d_ioctl = altqioctl,
176           .d_stop = nostop,
177           .d_tty = notty,
178           .d_poll = nopoll,
179           .d_mmap = nommap,
180           .d_kqfilter = nokqfilter,
181           .d_discard = nodiscard,
182           .d_flag = D_OTHER,
183 };
184 
185 int
altqopen(dev_t dev,int flag,int fmt,struct lwp * l)186 altqopen(dev_t dev, int flag, int fmt, struct lwp *l)
187 {
188           int unit = minor(dev);
189 
190           if (unit == 0)
191                     return 0;
192           if (unit < naltqsw)
193                     return (*altqsw[unit].d_open)(dev, flag, fmt, l);
194 
195           return ENXIO;
196 }
197 
198 int
altqclose(dev_t dev,int flag,int fmt,struct lwp * l)199 altqclose(dev_t dev, int flag, int fmt, struct lwp *l)
200 {
201           int unit = minor(dev);
202 
203           if (unit == 0)
204                     return 0;
205           if (unit < naltqsw)
206                     return (*altqsw[unit].d_close)(dev, flag, fmt, l);
207 
208           return ENXIO;
209 }
210 
211 int
altqioctl(dev_t dev,ioctlcmd_t cmd,void * addr,int flag,struct lwp * l)212 altqioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag, struct lwp *l)
213 {
214           int unit = minor(dev);
215 
216           if (unit == 0) {
217                     struct ifnet *ifp;
218                     struct altqreq *typereq;
219                     struct tbrreq *tbrreq;
220                     int error;
221 
222                     switch (cmd) {
223                     case ALTQGTYPE:
224                     case ALTQTBRGET:
225                               break;
226                     default:
227                               if ((error = kauth_authorize_network(
228                                   l->l_cred, KAUTH_NETWORK_ALTQ,
229                                   KAUTH_REQ_NETWORK_ALTQ_CONF, NULL, NULL,
230                                   NULL)) != 0)
231                                         return error;
232                               break;
233                     }
234 
235                     switch (cmd) {
236                     case ALTQGTYPE:
237                               typereq = (struct altqreq *)addr;
238                               if ((ifp = ifunit(typereq->ifname)) == NULL)
239                                         return (EINVAL);
240                               typereq->arg = (u_long)ifp->if_snd.altq_type;
241                               return 0;
242                     case ALTQTBRSET:
243                               tbrreq = (struct tbrreq *)addr;
244                               if ((ifp = ifunit(tbrreq->ifname)) == NULL)
245                                         return EINVAL;
246                               return tbr_set(&ifp->if_snd, &tbrreq->tb_prof);
247                     case ALTQTBRGET:
248                               tbrreq = (struct tbrreq *)addr;
249                               if ((ifp = ifunit(tbrreq->ifname)) == NULL)
250                                         return EINVAL;
251                               return tbr_get(&ifp->if_snd, &tbrreq->tb_prof);
252                     default:
253                               return EINVAL;
254                     }
255           }
256           if (unit < naltqsw)
257                     return (*altqsw[unit].d_ioctl)(dev, cmd, addr, flag, l);
258 
259           return ENXIO;
260 }
261 
262 #ifdef __FreeBSD__
263 static int altq_devsw_installed = 0;
264 #endif
265 
266 #ifdef __FreeBSD__
267 static void
altq_drvinit(void * unused)268 altq_drvinit(void *unused)
269 {
270           int unit;
271 
272 #if 0
273           mtx_init(&altq_mtx, "altq global lock", MTX_DEF);
274 #endif
275           altq_devsw_installed = 1;
276           printf("altq: attached. Major number assigned automatically.\n");
277 
278           /* create minor devices */
279           for (unit = 0; unit < naltqsw; unit++) {
280                     if (unit == 0 || altqsw[unit].d_open != NULL)
281                               altqsw[unit].dev = make_dev(&altq_cdevsw, unit,
282                                   UID_ROOT, GID_WHEEL, 0644, "altq/%s",
283                                   altqsw[unit].d_name);
284           }
285 }
286 
287 SYSINIT(altqdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,altq_drvinit,NULL)
288 
289 #endif /* FreeBSD */
290 
291 #ifdef ALTQ_KLD
292 /*
293  * KLD support
294  */
295 static int altq_module_register(struct altq_module_data *);
296 static int altq_module_deregister(struct altq_module_data *);
297 
298 static struct altq_module_data *altq_modules[ALTQT_MAX];
299 #if __FreeBSD_version < 502103
300 static struct altqsw noqdisc = {"noq", noopen, noclose, noioctl};
301 #else
302 static struct altqsw noqdisc = {"noq"};
303 #endif
304 
altq_module_incref(int type)305 void altq_module_incref(int type)
306 {
307           if (type < 0 || type >= ALTQT_MAX || altq_modules[type] == NULL)
308                     return;
309 
310           altq_modules[type]->ref++;
311 }
312 
altq_module_declref(int type)313 void altq_module_declref(int type)
314 {
315           if (type < 0 || type >= ALTQT_MAX || altq_modules[type] == NULL)
316                     return;
317 
318           altq_modules[type]->ref--;
319 }
320 
321 static int
altq_module_register(struct altq_module_data * mdata)322 altq_module_register(struct altq_module_data *mdata)
323 {
324           int type = mdata->type;
325 
326           if (type < 0 || type >= ALTQT_MAX)
327                     return EINVAL;
328 #if (__FreeBSD_version < 502103)
329           if (altqsw[type].d_open != noopen)
330 #else
331           if (altqsw[type].d_open != NULL)
332 #endif
333                     return EBUSY;
334           altqsw[type] = *mdata->altqsw;          /* set discipline functions */
335           altq_modules[type] = mdata;   /* save module data pointer */
336 #if (__FreeBSD_version < 502103)
337           make_dev(&altq_cdevsw, type, UID_ROOT, GID_WHEEL, 0644,
338                      "altq/%s", altqsw[type].d_name);
339 #else
340           altqsw[type].dev = make_dev(&altq_cdevsw, type, UID_ROOT, GID_WHEEL,
341               0644, "altq/%s", altqsw[type].d_name);
342 #endif
343           return 0;
344 }
345 
346 static int
altq_module_deregister(struct altq_module_data * mdata)347 altq_module_deregister(struct altq_module_data *mdata)
348 {
349           int type = mdata->type;
350 
351           if (type < 0 || type >= ALTQT_MAX)
352                     return EINVAL;
353           if (mdata != altq_modules[type])
354                     return EINVAL;
355           if (altq_modules[type]->ref > 0)
356                     return EBUSY;
357 #if (__FreeBSD_version < 502103)
358           destroy_dev(makedev(CDEV_MAJOR, type));
359 #else
360           destroy_dev(altqsw[type].dev);
361 #endif
362           altqsw[type] = noqdisc;
363           altq_modules[type] = NULL;
364           return 0;
365 }
366 
367 int
altq_module_handler(module_t mod,int cmd,void * arg)368 altq_module_handler(module_t mod, int cmd, void *arg)
369 {
370           struct altq_module_data *data = (struct altq_module_data *)arg;
371           int       error = 0;
372 
373           switch (cmd) {
374           case MOD_LOAD:
375                     error = altq_module_register(data);
376                     break;
377 
378           case MOD_UNLOAD:
379                     error = altq_module_deregister(data);
380                     break;
381 
382           default:
383                     error = EINVAL;
384                     break;
385           }
386 
387           return error;
388 }
389 
390 #endif  /* ALTQ_KLD */
391 #endif /* ALTQ3_COMPAT */
392