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 * $FreeBSD$
21 *
22 * altq interface
23 */
24
25#define PFIOC_USE_LATEST
26
27#include <sys/types.h>
28#include <sys/socket.h>
29#include <sys/sockio.h>
30
31#include "ipfw2.h"
32
33#include <err.h>
34#include <errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <sysexits.h>
39#include <unistd.h>
40#include <fcntl.h>
41
42#include <net/if.h>		/* IFNAMSIZ */
43#include <net/pfvar.h>
44#include <netinet/in.h>	/* in_addr */
45#include <netinet/ip_fw.h>
46
47/*
48 * Map between current altq queue id numbers and names.
49 */
50static TAILQ_HEAD(, pf_altq) altq_entries =
51	TAILQ_HEAD_INITIALIZER(altq_entries);
52
53void
54altq_set_enabled(int enabled)
55{
56	int pffd;
57
58	pffd = open("/dev/pf", O_RDWR);
59	if (pffd == -1)
60		err(EX_UNAVAILABLE,
61		    "altq support opening pf(4) control device");
62	if (enabled) {
63		if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST)
64			err(EX_UNAVAILABLE, "enabling altq");
65	} else {
66		if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT)
67			err(EX_UNAVAILABLE, "disabling altq");
68	}
69	close(pffd);
70}
71
72static void
73altq_fetch(void)
74{
75	struct pfioc_altq pfioc;
76	struct pf_altq *altq;
77	int pffd;
78	unsigned int mnr;
79	static int altq_fetched = 0;
80
81	if (altq_fetched)
82		return;
83	altq_fetched = 1;
84	pffd = open("/dev/pf", O_RDONLY);
85	if (pffd == -1) {
86		warn("altq support opening pf(4) control device");
87		return;
88	}
89	bzero(&pfioc, sizeof(pfioc));
90	pfioc.version = PFIOC_ALTQ_VERSION;
91	if (ioctl(pffd, DIOCGETALTQS, &pfioc) != 0) {
92		warn("altq support getting queue list");
93		close(pffd);
94		return;
95	}
96	mnr = pfioc.nr;
97	for (pfioc.nr = 0; pfioc.nr < mnr; pfioc.nr++) {
98		if (ioctl(pffd, DIOCGETALTQ, &pfioc) != 0) {
99			if (errno == EBUSY)
100				break;
101			warn("altq support getting queue list");
102			close(pffd);
103			return;
104		}
105		if (pfioc.altq.qid == 0)
106			continue;
107		altq = safe_calloc(1, sizeof(*altq));
108		*altq = pfioc.altq;
109		TAILQ_INSERT_TAIL(&altq_entries, altq, entries);
110	}
111	close(pffd);
112}
113
114u_int32_t
115altq_name_to_qid(const char *name)
116{
117	struct pf_altq *altq;
118
119	altq_fetch();
120	TAILQ_FOREACH(altq, &altq_entries, entries)
121		if (strcmp(name, altq->qname) == 0)
122			break;
123	if (altq == NULL)
124		errx(EX_DATAERR, "altq has no queue named `%s'", name);
125	return altq->qid;
126}
127
128static const char *
129altq_qid_to_name(u_int32_t qid)
130{
131	struct pf_altq *altq;
132
133	altq_fetch();
134	TAILQ_FOREACH(altq, &altq_entries, entries)
135		if (qid == altq->qid)
136			break;
137	if (altq == NULL)
138		return NULL;
139	return altq->qname;
140}
141
142void
143print_altq_cmd(struct buf_pr *bp, const ipfw_insn_altq *altqptr)
144{
145	if (altqptr) {
146		const char *qname;
147
148		qname = altq_qid_to_name(altqptr->qid);
149		if (qname == NULL)
150			bprintf(bp, " altq ?<%u>", altqptr->qid);
151		else
152			bprintf(bp, " altq %s", qname);
153	}
154}
155