1/*-
2 * Copyright (c) 2002-2003 Luigi Rizzo
3 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4 * Copyright (c) 1994 Ugen J.S.Antsilevich
5 *
6 * Idea and grammar partially left from:
7 * Copyright (c) 1993 Daniel Boulet
8 *
9 * Redistribution and use in source forms, with and without modification,
10 * are permitted provided that this entire comment appears intact.
11 *
12 * Redistribution in binary form may occur without any restrictions.
13 * Obviously, it would be nice if you gave credit where credit is due
14 * but requiring it would be too onerous.
15 *
16 * This software is provided ``AS IS'' without any warranties of any kind.
17 *
18 * NEW command line interface for IP firewall facility
19 *
20 * altq interface
21 */
22
23#define PFIOC_USE_LATEST
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/sockio.h>
28
29#include "ipfw2.h"
30
31#include <err.h>
32#include <errno.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <sysexits.h>
37#include <unistd.h>
38#include <fcntl.h>
39
40#include <net/if.h>		/* IFNAMSIZ */
41#include <net/pfvar.h>
42#include <netinet/in.h>	/* in_addr */
43#include <netinet/ip_fw.h>
44
45/*
46 * Map between current altq queue id numbers and names.
47 */
48static TAILQ_HEAD(, pf_altq) altq_entries =
49	TAILQ_HEAD_INITIALIZER(altq_entries);
50
51void
52altq_set_enabled(int enabled)
53{
54	int pffd;
55
56	pffd = open("/dev/pf", O_RDWR);
57	if (pffd == -1)
58		err(EX_UNAVAILABLE,
59		    "altq support opening pf(4) control device");
60	if (enabled) {
61		if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST)
62			err(EX_UNAVAILABLE, "enabling altq");
63	} else {
64		if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT)
65			err(EX_UNAVAILABLE, "disabling altq");
66	}
67	close(pffd);
68}
69
70static void
71altq_fetch(void)
72{
73	struct pfioc_altq pfioc;
74	struct pf_altq *altq;
75	int pffd;
76	unsigned int mnr;
77	static int altq_fetched = 0;
78
79	if (altq_fetched)
80		return;
81	altq_fetched = 1;
82	pffd = open("/dev/pf", O_RDONLY);
83	if (pffd == -1) {
84		warn("altq support opening pf(4) control device");
85		return;
86	}
87	bzero(&pfioc, sizeof(pfioc));
88	pfioc.version = PFIOC_ALTQ_VERSION;
89	if (ioctl(pffd, DIOCGETALTQS, &pfioc) != 0) {
90		warn("altq support getting queue list");
91		close(pffd);
92		return;
93	}
94	mnr = pfioc.nr;
95	for (pfioc.nr = 0; pfioc.nr < mnr; pfioc.nr++) {
96		if (ioctl(pffd, DIOCGETALTQ, &pfioc) != 0) {
97			if (errno == EBUSY)
98				break;
99			warn("altq support getting queue list");
100			close(pffd);
101			return;
102		}
103		if (pfioc.altq.qid == 0)
104			continue;
105		altq = safe_calloc(1, sizeof(*altq));
106		*altq = pfioc.altq;
107		TAILQ_INSERT_TAIL(&altq_entries, altq, entries);
108	}
109	close(pffd);
110}
111
112u_int32_t
113altq_name_to_qid(const char *name)
114{
115	struct pf_altq *altq;
116
117	altq_fetch();
118	TAILQ_FOREACH(altq, &altq_entries, entries)
119		if (strcmp(name, altq->qname) == 0)
120			break;
121	if (altq == NULL)
122		errx(EX_DATAERR, "altq has no queue named `%s'", name);
123	return altq->qid;
124}
125
126static const char *
127altq_qid_to_name(u_int32_t qid)
128{
129	struct pf_altq *altq;
130
131	altq_fetch();
132	TAILQ_FOREACH(altq, &altq_entries, entries)
133		if (qid == altq->qid)
134			break;
135	if (altq == NULL)
136		return NULL;
137	return altq->qname;
138}
139
140void
141print_altq_cmd(struct buf_pr *bp, const ipfw_insn_altq *altqptr)
142{
143	if (altqptr) {
144		const char *qname;
145
146		qname = altq_qid_to_name(altqptr->qid);
147		if (qname == NULL)
148			bprintf(bp, " altq ?<%u>", altqptr->qid);
149		else
150			bprintf(bp, " altq %s", qname);
151	}
152}
153