1*2fa9c3e7Srillig /* $NetBSD: quip_server.c,v 1.7 2024/10/04 15:37:00 rillig Exp $ */ 2d5e1f166Sitojun /* $KAME: quip_server.c,v 1.6 2001/08/20 06:41:32 kjc Exp $ */ 395a65560Sthorpej /* 495a65560Sthorpej * Copyright (C) 1999-2000 595a65560Sthorpej * Sony Computer Science Laboratories, Inc. All rights reserved. 695a65560Sthorpej * 795a65560Sthorpej * Redistribution and use in source and binary forms, with or without 895a65560Sthorpej * modification, are permitted provided that the following conditions 995a65560Sthorpej * are met: 1095a65560Sthorpej * 1. Redistributions of source code must retain the above copyright 1195a65560Sthorpej * notice, this list of conditions and the following disclaimer. 1295a65560Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 1395a65560Sthorpej * notice, this list of conditions and the following disclaimer in the 1495a65560Sthorpej * documentation and/or other materials provided with the distribution. 1595a65560Sthorpej * 1695a65560Sthorpej * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 1795a65560Sthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1895a65560Sthorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1995a65560Sthorpej * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 2095a65560Sthorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2195a65560Sthorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2295a65560Sthorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2395a65560Sthorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2495a65560Sthorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2595a65560Sthorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2695a65560Sthorpej * SUCH DAMAGE. 2795a65560Sthorpej */ 2895a65560Sthorpej 2995a65560Sthorpej #include <sys/param.h> 3095a65560Sthorpej #include <sys/socket.h> 3195a65560Sthorpej #include <sys/queue.h> 3295a65560Sthorpej 3395a65560Sthorpej #include <net/if.h> 3495a65560Sthorpej #include <netinet/in.h> 3595a65560Sthorpej #include <arpa/inet.h> 3695a65560Sthorpej 3795a65560Sthorpej #include <stdio.h> 3895a65560Sthorpej #include <stdlib.h> 3995a65560Sthorpej #include <unistd.h> 4095a65560Sthorpej #include <stddef.h> 4195a65560Sthorpej #include <string.h> 4295a65560Sthorpej #include <errno.h> 4395a65560Sthorpej #include <err.h> 4495a65560Sthorpej 4595a65560Sthorpej #include <altq/altq.h> 4695a65560Sthorpej #include <altq/altq_red.h> 4795a65560Sthorpej #include <altq/altq_rio.h> 4895a65560Sthorpej 4995a65560Sthorpej #include "altq_qop.h" 5095a65560Sthorpej #include "quip_server.h" 5195a65560Sthorpej 5295a65560Sthorpej extern LIST_HEAD(qop_iflist, ifinfo) qop_iflist; 5395a65560Sthorpej 5495a65560Sthorpej #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0) 5595a65560Sthorpej 568b8734d2Sitojun static int next_word(char **, char *); 5795a65560Sthorpej 588b8734d2Sitojun static int query_list(const char *, const char *, char *, size_t); 598b8734d2Sitojun static int query_handle2name(const char *, const char *, char *, size_t); 608b8734d2Sitojun static int query_qdisc(const char *, const char *, char *, size_t); 618b8734d2Sitojun static int query_filterspec(const char *, const char *, char *, size_t); 6295a65560Sthorpej 6395a65560Sthorpej int 6495a65560Sthorpej quip_input(FILE *fp) 6595a65560Sthorpej { 668b8734d2Sitojun char request[REQ_MAXSIZE], result[RES_MAXSIZE], body[BODY_MAXSIZE], 678b8734d2Sitojun w[REQ_MAXSIZE], *cp, *query; 6895a65560Sthorpej int n = 0; 6995a65560Sthorpej 7095a65560Sthorpej while (1) { 718b8734d2Sitojun if (fgets(request, REQ_MAXSIZE, fp) == NULL) /* EOF */ 7295a65560Sthorpej return (-1); 7395a65560Sthorpej /* skip preceding blank lines */ 7495a65560Sthorpej if (request[0] == '\n') 7595a65560Sthorpej continue; 7695a65560Sthorpej break; 7795a65560Sthorpej } 7895a65560Sthorpej 7995a65560Sthorpej /* remove trailing newline and white space */ 8095a65560Sthorpej if ((cp = strrchr(request, '\n')) != NULL) { 8195a65560Sthorpej *cp-- = '\0'; 8295a65560Sthorpej while (*cp == ' ' || *cp == '\t') 8395a65560Sthorpej *cp-- = '\0'; 8495a65560Sthorpej } 8595a65560Sthorpej 8695a65560Sthorpej body[0] = '\0'; 8795a65560Sthorpej cp = request; 8895a65560Sthorpej if (!next_word(&cp, w)) { 898b8734d2Sitojun snprintf(result, sizeof(result), "400 Bad request\n"); 9095a65560Sthorpej goto done; 9195a65560Sthorpej } 9295a65560Sthorpej if (EQUAL(w, "GET")) { 9395a65560Sthorpej if (!next_word(&cp, w)) { 948b8734d2Sitojun snprintf(result, sizeof(result), "400 Bad request\n"); 9595a65560Sthorpej goto done; 9695a65560Sthorpej } 9795a65560Sthorpej if ((query = strchr(w, '?')) != NULL) { 9895a65560Sthorpej /* request has a query string */ 9995a65560Sthorpej *query = '\0'; 10095a65560Sthorpej query++; 10195a65560Sthorpej } 10295a65560Sthorpej 10395a65560Sthorpej if (EQUAL(w, "list")) { 1048b8734d2Sitojun n = query_list(w, query, body, BODY_MAXSIZE); 10595a65560Sthorpej } else if (EQUAL(w, "handle-to-name")) { 1068b8734d2Sitojun n = query_handle2name(w, query, body, BODY_MAXSIZE); 10795a65560Sthorpej } else if (EQUAL(w, "qdisc")) { 1088b8734d2Sitojun n = query_qdisc(w, query, body, BODY_MAXSIZE); 10995a65560Sthorpej } else if (EQUAL(w, "filter")) { 1108b8734d2Sitojun n = query_filterspec(w, query, body, BODY_MAXSIZE); 11195a65560Sthorpej } else { 1128b8734d2Sitojun snprintf(result, sizeof(result), "400 Bad request\n"); 11395a65560Sthorpej goto done; 11495a65560Sthorpej } 11595a65560Sthorpej } else { 1168b8734d2Sitojun snprintf(result, sizeof(result), "400 Bad request\n"); 11795a65560Sthorpej goto done; 11895a65560Sthorpej } 11995a65560Sthorpej 12095a65560Sthorpej if (n == 0) { 1218b8734d2Sitojun snprintf(result, sizeof(result), "204 No content\n"); 12295a65560Sthorpej } else if (n < 0) { 1238b8734d2Sitojun snprintf(result, sizeof(result), "400 Bad request\n"); 12495a65560Sthorpej } else { 1258b8734d2Sitojun snprintf(result, sizeof(result), "200 OK\nContent-Length:%d\n", n); 12695a65560Sthorpej } 12795a65560Sthorpej 12895a65560Sthorpej done: 12995a65560Sthorpej /* send a result line and a blank line */ 13095a65560Sthorpej if (fputs ("QUIP/1.0 ", fp) != 0 || 13195a65560Sthorpej fputs(result, fp) != 0 || fputs("\n", fp) != 0) 13295a65560Sthorpej return (-1); 13395a65560Sthorpej 13495a65560Sthorpej /* send message body */ 13595a65560Sthorpej if (fputs(body, fp) != 0) 13695a65560Sthorpej return (-1); 13795a65560Sthorpej return (0); 13895a65560Sthorpej } 13995a65560Sthorpej 14095a65560Sthorpej /* 14195a65560Sthorpej * Skip leading blanks, then copy next word (delimited by blank or zero, but 14295a65560Sthorpej * no longer than 63 bytes) into buffer b, set scan pointer to following 14395a65560Sthorpej * non-blank (or end of string), and return 1. If there is no non-blank text, 14495a65560Sthorpej * set scan ptr to point to 0 byte and return 0. 14595a65560Sthorpej */ 14695a65560Sthorpej static int 14795a65560Sthorpej next_word(char **cpp, char *b) 14895a65560Sthorpej { 14995a65560Sthorpej char *tp; 15095a65560Sthorpej int L; 15195a65560Sthorpej 15295a65560Sthorpej *cpp += strspn(*cpp, " \t"); 15395a65560Sthorpej if (**cpp == '\0' || **cpp == '\n' || **cpp == '#') 15495a65560Sthorpej return(0); 15595a65560Sthorpej 15695a65560Sthorpej tp = strpbrk(*cpp, " \t\n#"); 1577affd655Slukem L = MIN((tp)?(tp-*cpp):(int)strlen(*cpp), 63); 15895a65560Sthorpej strncpy(b, *cpp, L); 15995a65560Sthorpej *(b + L) = '\0'; 16095a65560Sthorpej *cpp += L; 16195a65560Sthorpej *cpp += strspn(*cpp, " \t"); 16295a65560Sthorpej return (1); 16395a65560Sthorpej } 16495a65560Sthorpej 16595a65560Sthorpej 16695a65560Sthorpej /* 16795a65560Sthorpej * expand_classname creates a long class name. 16895a65560Sthorpej * <ifname>:/<root_name>/../<parent_name>/<class_name> 16995a65560Sthorpej */ 17095a65560Sthorpej static int 1718b8734d2Sitojun expand_classname(struct classinfo *clinfo, char *name, size_t maxname) 17295a65560Sthorpej { 17395a65560Sthorpej struct classinfo *ci = clinfo; 1748b8734d2Sitojun #define CLASSNAMEMAX 256 1758b8734d2Sitojun char buf[2][CLASSNAMEMAX], *b0, *b1, *tmp; 17695a65560Sthorpej 17795a65560Sthorpej b0 = buf[0]; b1 = buf[1]; 17895a65560Sthorpej b1[0] = '\0'; 17995a65560Sthorpej while (ci != NULL) { 1808b8734d2Sitojun strlcpy(b0, "/", CLASSNAMEMAX); 1818b8734d2Sitojun strlcat(b0, ci->clname, CLASSNAMEMAX); 1828b8734d2Sitojun strlcat(b0, b1, CLASSNAMEMAX); 18395a65560Sthorpej 18495a65560Sthorpej ci = ci->parent; 18595a65560Sthorpej tmp = b0; b0 = b1; b1 = tmp; 18695a65560Sthorpej } 1878b8734d2Sitojun snprintf(b0, CLASSNAMEMAX, "%s:", clinfo->ifinfo->ifname); 1888b8734d2Sitojun strlcat(b0, b1, CLASSNAMEMAX); 1898b8734d2Sitojun strlcpy(name, b0, CLASSNAMEMAX); 19095a65560Sthorpej return (strlen(name)); 1918b8734d2Sitojun #undef CLASSNAMEMAX 19295a65560Sthorpej } 19395a65560Sthorpej 19495a65560Sthorpej /* 19595a65560Sthorpej * expand_filtername creates a long filter name. 19695a65560Sthorpej * <ifname>:/<root_name>/../<parent_name>/<class_name>:<fltr_name> 19795a65560Sthorpej */ 19895a65560Sthorpej static int 1998b8734d2Sitojun expand_filtername(struct fltrinfo *fltrinfo, char *name, size_t maxname) 20095a65560Sthorpej { 20195a65560Sthorpej int len; 20295a65560Sthorpej 2038b8734d2Sitojun len = expand_classname(fltrinfo->clinfo, name, maxname); 204d5e1f166Sitojun snprintf(name + len, maxname - len, ":%s", fltrinfo->flname); 205d5e1f166Sitojun return (strlen(name)); 20695a65560Sthorpej } 20795a65560Sthorpej 20895a65560Sthorpej static int 2098b8734d2Sitojun query_handle2name(const char *cmd, const char *arg, char *msg, size_t maxmsg) 21095a65560Sthorpej { 21195a65560Sthorpej struct ifinfo *ifinfo; 21295a65560Sthorpej struct classinfo *clinfo; 21395a65560Sthorpej struct fltrinfo *fltrinfo; 21495a65560Sthorpej char *ifname, *class_field, *fltr_field, buf[256], *cp; 21595a65560Sthorpej u_long handle; 21695a65560Sthorpej 2178b8734d2Sitojun strlcpy(buf, arg, sizeof(buf)); 21895a65560Sthorpej cp = buf; 21995a65560Sthorpej ifname = strsep(&cp, ":"); 22095a65560Sthorpej class_field = strsep(&cp, ":"); 22195a65560Sthorpej fltr_field = cp; 22295a65560Sthorpej 22395a65560Sthorpej if (fltr_field != NULL) { 22495a65560Sthorpej if (sscanf(fltr_field, "%lx", &handle) != 1) 22595a65560Sthorpej return (-1); 22695a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 22795a65560Sthorpej return (-1); 22895a65560Sthorpej if ((fltrinfo = flhandle2fltrinfo(ifinfo, handle)) == NULL) 22995a65560Sthorpej return (-1); 23095a65560Sthorpej 2310a77b69aSchristos (void)expand_filtername(fltrinfo, msg, maxmsg); 23295a65560Sthorpej } else { 23395a65560Sthorpej if (sscanf(class_field, "%lx", &handle) != 1) 23495a65560Sthorpej return (-1); 23595a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 23695a65560Sthorpej return (-1); 23795a65560Sthorpej if ((clinfo = clhandle2clinfo(ifinfo, handle)) == NULL) 23895a65560Sthorpej return (-1); 23995a65560Sthorpej 2400a77b69aSchristos (void)expand_classname(clinfo, msg, maxmsg); 24195a65560Sthorpej } 242d5e1f166Sitojun strlcat(msg, "\n", maxmsg); 243d5e1f166Sitojun return (strlen(msg)); 24495a65560Sthorpej } 24595a65560Sthorpej 24695a65560Sthorpej static int 2478b8734d2Sitojun query_qdisc(const char *cmd, const char *arg, char *msg, size_t maxmsg) 24895a65560Sthorpej { 24995a65560Sthorpej struct ifinfo *ifinfo; 25095a65560Sthorpej 25195a65560Sthorpej if ((ifinfo = ifname2ifinfo(arg)) == NULL) 25295a65560Sthorpej return (-1); 25395a65560Sthorpej 254d5e1f166Sitojun snprintf(msg, maxmsg, "%s\nbandwidth:%.2fMbps\nstatus:%s\n", 25595a65560Sthorpej ifinfo->qdisc->qname, (double)ifinfo->bandwidth/1000000, 25695a65560Sthorpej (ifinfo->enabled ? "enabled" : "disabled")); 257d5e1f166Sitojun return (strlen(msg)); 25895a65560Sthorpej } 25995a65560Sthorpej 26095a65560Sthorpej static int 2618b8734d2Sitojun query_filterspec(const char *cmd, const char *arg, char *msg, size_t maxmsg) 26295a65560Sthorpej { 26395a65560Sthorpej struct ifinfo *ifinfo; 26495a65560Sthorpej struct fltrinfo *fltrinfo; 26595a65560Sthorpej struct flow_filter *filt; 2660a77b69aSchristos char *ifname, *fltr_field, buf[256], *cp; 26795a65560Sthorpej u_long handle; 26895a65560Sthorpej 2698b8734d2Sitojun strlcpy(buf, arg, sizeof(buf)); 27095a65560Sthorpej cp = buf; 27195a65560Sthorpej ifname = strsep(&cp, ":"); 2720a77b69aSchristos (void)strsep(&cp, ":"); 27395a65560Sthorpej fltr_field = cp; 27495a65560Sthorpej 27595a65560Sthorpej if (fltr_field == NULL) 27695a65560Sthorpej return (-1); 27795a65560Sthorpej if (sscanf(fltr_field, "%lx", &handle) != 1) 27895a65560Sthorpej return (-1); 27995a65560Sthorpej 28095a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 28195a65560Sthorpej return (-1); 28295a65560Sthorpej if ((fltrinfo = flhandle2fltrinfo(ifinfo, handle)) == NULL) 28395a65560Sthorpej return (-1); 28495a65560Sthorpej 28595a65560Sthorpej filt = &fltrinfo->fltr; 28695a65560Sthorpej 28795a65560Sthorpej if (filt->ff_flow.fi_family == AF_INET) { 28895a65560Sthorpej char src[128], dst[128], smask[128], dmask[128], tos[128]; 28995a65560Sthorpej 29095a65560Sthorpej if (filt->ff_flow.fi_dst.s_addr == 0) { 2918b8734d2Sitojun snprintf(dst, sizeof(dst), "0"); 29295a65560Sthorpej dmask[0] = '\0'; 29395a65560Sthorpej } else { 2948b8734d2Sitojun snprintf(dst, sizeof(dst), "%s", 2958b8734d2Sitojun inet_ntoa(filt->ff_flow.fi_dst)); 29695a65560Sthorpej if (filt->ff_mask.mask_dst.s_addr == 0xffffffff) 29795a65560Sthorpej dmask[0] = '\0'; 29895a65560Sthorpej else 2998b8734d2Sitojun snprintf(dmask, sizeof(dmask), " mask %#x", 30095a65560Sthorpej ntoh32(filt->ff_mask.mask_dst.s_addr)); 30195a65560Sthorpej } 30295a65560Sthorpej if (filt->ff_flow.fi_src.s_addr == 0) { 3038b8734d2Sitojun snprintf(src, sizeof(src), "0"); 30495a65560Sthorpej smask[0] = '\0'; 30595a65560Sthorpej } else { 3068b8734d2Sitojun snprintf(src, sizeof(src), "%s", 3078b8734d2Sitojun inet_ntoa(filt->ff_flow.fi_src)); 30895a65560Sthorpej if (filt->ff_mask.mask_src.s_addr == 0xffffffff) 30995a65560Sthorpej smask[0] = '\0'; 31095a65560Sthorpej else 3118b8734d2Sitojun snprintf(smask, sizeof(smask), " mask %#x", 31295a65560Sthorpej ntoh32(filt->ff_mask.mask_src.s_addr)); 31395a65560Sthorpej } 31495a65560Sthorpej if (filt->ff_flow.fi_tos == 0) 31595a65560Sthorpej tos[0] = '\0'; 31695a65560Sthorpej else 3178b8734d2Sitojun snprintf(tos, sizeof(tos), " tos %#x tosmask %#x", 31895a65560Sthorpej filt->ff_flow.fi_tos, 31995a65560Sthorpej filt->ff_mask.mask_tos); 32095a65560Sthorpej 321d5e1f166Sitojun snprintf(msg, maxmsg, "inet %s%s %d %s%s %d %d%s\n", 32295a65560Sthorpej dst, dmask, 32395a65560Sthorpej ntoh16(filt->ff_flow.fi_dport), 32495a65560Sthorpej src, smask, 32595a65560Sthorpej ntoh16(filt->ff_flow.fi_sport), 32695a65560Sthorpej filt->ff_flow.fi_proto, tos); 32795a65560Sthorpej } 32895a65560Sthorpej #ifdef INET6 32995a65560Sthorpej else if (filt->ff_flow.fi_family == AF_INET6) { 33095a65560Sthorpej struct flow_filter6 *filt6; 33195a65560Sthorpej char dst6[INET6_ADDRSTRLEN], dmask6[INET6_ADDRSTRLEN]; 33295a65560Sthorpej char src6[INET6_ADDRSTRLEN], smask6[INET6_ADDRSTRLEN]; 33395a65560Sthorpej char tclass6[128]; 33495a65560Sthorpej const struct in6_addr mask128 = 33595a65560Sthorpej {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 33695a65560Sthorpej 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}; 33795a65560Sthorpej 33895a65560Sthorpej filt6 = (struct flow_filter6 *)&fltrinfo->fltr; 33995a65560Sthorpej if (IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_dst)) { 3408b8734d2Sitojun snprintf(dst6, sizeof(dst6), "0"); 34195a65560Sthorpej dmask6[0] = '\0'; 34295a65560Sthorpej } else { 34395a65560Sthorpej inet_ntop(AF_INET6, &filt6->ff_flow6.fi6_dst, 34495a65560Sthorpej dst6, sizeof(dst6)); 34595a65560Sthorpej if (IN6_ARE_ADDR_EQUAL(&mask128, 34695a65560Sthorpej &filt6->ff_mask6.mask6_dst)) 34795a65560Sthorpej dmask6[0] = '\0'; 34895a65560Sthorpej else { 3498b8734d2Sitojun snprintf(dmask6, sizeof(dmask6), " mask "); 35095a65560Sthorpej inet_ntop(AF_INET6, &filt6->ff_mask6.mask6_dst, 35195a65560Sthorpej dmask6 + 6, sizeof(dmask6) -6); 35295a65560Sthorpej } 35395a65560Sthorpej } 35495a65560Sthorpej 35595a65560Sthorpej if (IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_src)) { 3568b8734d2Sitojun snprintf(src6, sizeof(src6), "0"); 35795a65560Sthorpej smask6[0] = '\0'; 35895a65560Sthorpej } else { 35995a65560Sthorpej inet_ntop(AF_INET6, &filt6->ff_flow6.fi6_src, 36095a65560Sthorpej src6, sizeof(src6)); 36195a65560Sthorpej if (IN6_ARE_ADDR_EQUAL(&mask128, 36295a65560Sthorpej &filt6->ff_mask6.mask6_src)) 36395a65560Sthorpej smask6[0] = '\0'; 36495a65560Sthorpej else { 3658b8734d2Sitojun snprintf(smask6, sizeof(smask6), " mask "); 36695a65560Sthorpej inet_ntop(AF_INET6, &filt6->ff_mask6.mask6_src, 36795a65560Sthorpej smask6 + 6, sizeof(smask6) -6); 36895a65560Sthorpej } 36995a65560Sthorpej } 37095a65560Sthorpej if (filt6->ff_flow6.fi6_tclass == 0) 37195a65560Sthorpej tclass6[0] = '\0'; 37295a65560Sthorpej else 3738b8734d2Sitojun snprintf(tclass6, sizeof(tclass6), 3748b8734d2Sitojun " tclass %#x tclassmask %#x", 37595a65560Sthorpej filt6->ff_flow6.fi6_tclass, 37695a65560Sthorpej filt6->ff_mask6.mask6_tclass); 37795a65560Sthorpej 378d5e1f166Sitojun snprintf(msg, maxmsg, "inet6 %s%s %d %s%s %d %d%s\n", 37995a65560Sthorpej dst6, dmask6, 38095a65560Sthorpej ntoh16(filt6->ff_flow6.fi6_dport), 38195a65560Sthorpej src6, smask6, 38295a65560Sthorpej ntoh16(filt6->ff_flow6.fi6_sport), 38395a65560Sthorpej filt6->ff_flow6.fi6_proto, tclass6); 38495a65560Sthorpej } 38595a65560Sthorpej #endif /* INET6 */ 38695a65560Sthorpej 387d5e1f166Sitojun return (strlen(msg)); 38895a65560Sthorpej } 38995a65560Sthorpej 39095a65560Sthorpej 39195a65560Sthorpej /* 39295a65560Sthorpej * string_match compares 2 strings and returns 1 when s1 matches s2. 39395a65560Sthorpej * s1: possibly includes wildcards, "*". 39495a65560Sthorpej * s2: must be a full string (should not include "*"). 39595a65560Sthorpej */ 39695a65560Sthorpej static int 39795a65560Sthorpej string_match(const char *s1, const char *s2) 39895a65560Sthorpej { 39995a65560Sthorpej char *ap, *next, sub[256]; 40095a65560Sthorpej int prefixlen, sublen; 40195a65560Sthorpej 40295a65560Sthorpej /* if there's no wild card, compare full string */ 40395a65560Sthorpej if ((ap = strchr(s1, '*')) == NULL) 40495a65560Sthorpej return (strcmp(s1, s2) == 0); 40595a65560Sthorpej 40695a65560Sthorpej /* compare string prefix */ 40795a65560Sthorpej prefixlen = ap - s1; 40895a65560Sthorpej if (strncmp(s1, s2, prefixlen) != 0) 40995a65560Sthorpej return (0); 41095a65560Sthorpej s2 += prefixlen; 41195a65560Sthorpej 41295a65560Sthorpej /* 41395a65560Sthorpej * if there is another wildcard in the rest of the string, 41495a65560Sthorpej * compare the substring between the 2 wildcards. 41595a65560Sthorpej */ 41695a65560Sthorpej while ((next = strchr(ap + 1, '*')) != NULL) { 41795a65560Sthorpej sublen = next - ap - 1; 41895a65560Sthorpej strncpy(sub, ap+1, sublen); 41995a65560Sthorpej sub[sublen] = '\0'; 42095a65560Sthorpej if ((s2 = strstr(s2, sub)) == NULL) 42195a65560Sthorpej return (0); 42295a65560Sthorpej 42395a65560Sthorpej s2 += sublen; 42495a65560Sthorpej ap = next; 42595a65560Sthorpej } 42695a65560Sthorpej 42795a65560Sthorpej /* no more wildcard, compare the rest of the string */ 42895a65560Sthorpej return (strcmp(ap+1, s2+strlen(s2)-strlen(ap+1)) == 0); 42995a65560Sthorpej } 43095a65560Sthorpej 43195a65560Sthorpej static int 4328b8734d2Sitojun query_list(const char *cmd, const char *arg, char *msg, size_t maxmsg) 43395a65560Sthorpej { 434*2fa9c3e7Srillig const char *colon; 4358b8734d2Sitojun char tmp[256], *cp, *ep; 43695a65560Sthorpej struct ifinfo *ifinfo; 43795a65560Sthorpej struct classinfo *clinfo; 43895a65560Sthorpej struct fltrinfo *fltrinfo; 439d5e1f166Sitojun int print_if, print_class, print_fltr, len; 44095a65560Sthorpej 44195a65560Sthorpej if (arg == NULL) { 44295a65560Sthorpej /* no arg, print all */ 44395a65560Sthorpej print_if = print_class = print_fltr = 1; 44495a65560Sthorpej } else { 44595a65560Sthorpej print_if = print_class = print_fltr = 0; 446*2fa9c3e7Srillig if ((colon = strchr(arg, ':')) == NULL) 44795a65560Sthorpej print_if = 1; 448*2fa9c3e7Srillig else if (strchr(colon+1, ':') == NULL) 44995a65560Sthorpej print_class = 1; 45095a65560Sthorpej else 45195a65560Sthorpej print_fltr = 1; 45295a65560Sthorpej } 45395a65560Sthorpej 45495a65560Sthorpej cp = msg; 4558b8734d2Sitojun ep = msg + maxmsg; 45695a65560Sthorpej LIST_FOREACH(ifinfo, &qop_iflist, next) { 45795a65560Sthorpej if (print_if) { 4588b8734d2Sitojun strlcpy(tmp, ifinfo->ifname, sizeof(tmp)); 459d5e1f166Sitojun if (arg == NULL || string_match(arg, tmp)) { 460d5e1f166Sitojun len = snprintf(cp, ep - cp, "%#010x\t%s\n", 46195a65560Sthorpej ifinfo->ifindex, tmp); 462d5e1f166Sitojun if (len < 0 || len >= ep - cp) 463d5e1f166Sitojun break; 464d5e1f166Sitojun cp += len; 465d5e1f166Sitojun } 46695a65560Sthorpej } 46795a65560Sthorpej if (!print_class && !print_fltr) 46895a65560Sthorpej continue; 46995a65560Sthorpej for (clinfo = get_rootclass(ifinfo); 47095a65560Sthorpej clinfo != NULL; clinfo = get_nextclass(clinfo)) { 47195a65560Sthorpej if (print_class) { 4728b8734d2Sitojun expand_classname(clinfo, tmp, sizeof(tmp)); 473d5e1f166Sitojun if (arg == NULL || string_match(arg, tmp)) { 474d5e1f166Sitojun len = snprintf(cp, ep - cp, 4758b8734d2Sitojun "%#010lx\t%s\n", 47695a65560Sthorpej clinfo->handle, tmp); 477d5e1f166Sitojun if (len < 0 || len >= ep - cp) 478d5e1f166Sitojun break; 479d5e1f166Sitojun cp += len; 480d5e1f166Sitojun } 48195a65560Sthorpej } 48295a65560Sthorpej if (!print_fltr) 48395a65560Sthorpej continue; 48495a65560Sthorpej LIST_FOREACH(fltrinfo, &clinfo->fltrlist, next) { 4858b8734d2Sitojun expand_filtername(fltrinfo, tmp, sizeof(tmp)); 486d5e1f166Sitojun if (arg == NULL || string_match(arg, tmp)) { 487d5e1f166Sitojun len = snprintf(cp, ep - cp, "%#010lx\t%s\n", 48895a65560Sthorpej fltrinfo->handle, tmp); 489d5e1f166Sitojun if (len < 0 || len >= ep - cp) 490d5e1f166Sitojun break; 491d5e1f166Sitojun cp += len; 49295a65560Sthorpej } 49395a65560Sthorpej } 49495a65560Sthorpej } 495d5e1f166Sitojun } 496d5e1f166Sitojun return (strlen(msg)); 49795a65560Sthorpej } 49895a65560Sthorpej 499