mibII_udp.c revision 146525
143615Sdcs/* 243615Sdcs * Copyright (c) 2001-2003 343615Sdcs * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 443615Sdcs * All rights reserved. 543615Sdcs * 643615Sdcs * Author: Harti Brandt <harti@freebsd.org> 743615Sdcs * 843615Sdcs * Redistribution and use in source and binary forms, with or without 943615Sdcs * modification, are permitted provided that the following conditions 1043615Sdcs * are met: 1143615Sdcs * 1. Redistributions of source code must retain the above copyright 1243615Sdcs * notice, this list of conditions and the following disclaimer. 1343615Sdcs * 2. Redistributions in binary form must reproduce the above copyright 1443615Sdcs * notice, this list of conditions and the following disclaimer in the 1543615Sdcs * documentation and/or other materials provided with the distribution. 1643615Sdcs * 1743615Sdcs * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1843615Sdcs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1943615Sdcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2043615Sdcs * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 2143615Sdcs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2243615Sdcs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2343615Sdcs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2443615Sdcs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2544774Sdcs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2643615Sdcs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2743615Sdcs * SUCH DAMAGE. 2843615Sdcs * 2943615Sdcs * $Begemot: bsnmp/snmp_mibII/mibII_udp.c,v 1.7 2005/05/23 09:03:42 brandt_h Exp $ 3043615Sdcs * 3143615Sdcs * udp 3243615Sdcs */ 3344774Sdcs#include "mibII.h" 3443615Sdcs#include "mibII_oid.h" 3543615Sdcs#include <sys/socketvar.h> 3643615Sdcs#include <netinet/in_pcb.h> 37#include <netinet/udp.h> 38#include <netinet/ip_var.h> 39#include <netinet/udp_var.h> 40 41struct udp_index { 42 struct asn_oid index; 43 struct xinpcb *inp; 44}; 45 46static uint64_t udp_tick; 47static struct udpstat udpstat; 48static struct xinpgen *xinpgen; 49static size_t xinpgen_len; 50static u_int udp_total; 51 52static u_int oidnum; 53static struct udp_index *udpoids; 54 55static int 56udp_compare(const void *p1, const void *p2) 57{ 58 const struct udp_index *t1 = p1; 59 const struct udp_index *t2 = p2; 60 61 return (asn_compare_oid(&t1->index, &t2->index)); 62} 63 64static int 65fetch_udp(void) 66{ 67 size_t len; 68 struct xinpgen *ptr; 69 struct xinpcb *inp; 70 struct udp_index *oid; 71 in_addr_t inaddr; 72 73 len = sizeof(udpstat); 74 if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, NULL, 0) == -1) { 75 syslog(LOG_ERR, "net.inet.udp.stats: %m"); 76 return (-1); 77 } 78 if (len != sizeof(udpstat)) { 79 syslog(LOG_ERR, "net.inet.udp.stats: wrong size"); 80 return (-1); 81 } 82 83 udp_tick = get_ticks(); 84 85 len = 0; 86 if (sysctlbyname("net.inet.udp.pcblist", NULL, &len, NULL, 0) == -1) { 87 syslog(LOG_ERR, "net.inet.udp.pcblist: %m"); 88 return (-1); 89 } 90 if (len > xinpgen_len) { 91 if ((ptr = realloc(xinpgen, len)) == NULL) { 92 syslog(LOG_ERR, "%zu: %m", len); 93 return (-1); 94 } 95 xinpgen = ptr; 96 xinpgen_len = len; 97 } 98 if (sysctlbyname("net.inet.udp.pcblist", xinpgen, &len, NULL, 0) == -1) { 99 syslog(LOG_ERR, "net.inet.udp.pcblist: %m"); 100 return (-1); 101 } 102 103 udp_total = 0; 104 for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); 105 ptr->xig_len > sizeof(struct xinpgen); 106 ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { 107 inp = (struct xinpcb *)ptr; 108 if (inp->xi_inp.inp_gencnt > xinpgen->xig_gen || 109 (inp->xi_inp.inp_vflag & INP_IPV4) == 0) 110 continue; 111 112 udp_total++; 113 } 114 115 if (oidnum < udp_total) { 116 oid = realloc(udpoids, udp_total * sizeof(udpoids[0])); 117 if (oid == NULL) { 118 free(udpoids); 119 oidnum = 0; 120 return (0); 121 } 122 udpoids = oid; 123 oidnum = udp_total; 124 } 125 126 oid = udpoids; 127 for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); 128 ptr->xig_len > sizeof(struct xinpgen); 129 ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { 130 inp = (struct xinpcb *)ptr; 131 if (inp->xi_inp.inp_gencnt > xinpgen->xig_gen || 132 (inp->xi_inp.inp_vflag & INP_IPV4) == 0) 133 continue; 134 oid->inp = inp; 135 oid->index.len = 5; 136 inaddr = ntohl(inp->xi_inp.inp_laddr.s_addr); 137 oid->index.subs[0] = (inaddr >> 24) & 0xff; 138 oid->index.subs[1] = (inaddr >> 16) & 0xff; 139 oid->index.subs[2] = (inaddr >> 8) & 0xff; 140 oid->index.subs[3] = (inaddr >> 0) & 0xff; 141 oid->index.subs[4] = ntohs(inp->xi_inp.inp_lport); 142 oid++; 143 } 144 145 qsort(udpoids, udp_total, sizeof(udpoids[0]), udp_compare); 146 147 return (0); 148} 149 150int 151op_udp(struct snmp_context *ctx __unused, struct snmp_value *value, 152 u_int sub, u_int iidx __unused, enum snmp_op op) 153{ 154 switch (op) { 155 156 case SNMP_OP_GETNEXT: 157 abort(); 158 159 case SNMP_OP_GET: 160 break; 161 162 case SNMP_OP_SET: 163 return (SNMP_ERR_NOT_WRITEABLE); 164 165 case SNMP_OP_ROLLBACK: 166 case SNMP_OP_COMMIT: 167 abort(); 168 } 169 170 if (udp_tick < this_tick) 171 if (fetch_udp() == -1) 172 return (SNMP_ERR_GENERR); 173 174 switch (value->var.subs[sub - 1]) { 175 176 case LEAF_udpInDatagrams: 177 value->v.uint32 = udpstat.udps_ipackets; 178 break; 179 180 case LEAF_udpNoPorts: 181 value->v.uint32 = udpstat.udps_noport + 182 udpstat.udps_noportbcast + 183 udpstat.udps_noportmcast; 184 break; 185 186 case LEAF_udpInErrors: 187 value->v.uint32 = udpstat.udps_hdrops + 188 udpstat.udps_badsum + 189 udpstat.udps_badlen + 190 udpstat.udps_fullsock; 191 break; 192 193 case LEAF_udpOutDatagrams: 194 value->v.uint32 = udpstat.udps_opackets; 195 break; 196 } 197 return (SNMP_ERR_NOERROR); 198} 199 200int 201op_udptable(struct snmp_context *ctx __unused, struct snmp_value *value, 202 u_int sub, u_int iidx __unused, enum snmp_op op) 203{ 204 u_int i; 205 206 if (udp_tick < this_tick) 207 if (fetch_udp() == -1) 208 return (SNMP_ERR_GENERR); 209 210 switch (op) { 211 212 case SNMP_OP_GETNEXT: 213 for (i = 0; i < udp_total; i++) 214 if (index_compare(&value->var, sub, &udpoids[i].index) < 0) 215 break; 216 if (i == udp_total) 217 return (SNMP_ERR_NOSUCHNAME); 218 index_append(&value->var, sub, &udpoids[i].index); 219 break; 220 221 case SNMP_OP_GET: 222 for (i = 0; i < udp_total; i++) 223 if (index_compare(&value->var, sub, &udpoids[i].index) == 0) 224 break; 225 if (i == udp_total) 226 return (SNMP_ERR_NOSUCHNAME); 227 break; 228 229 case SNMP_OP_SET: 230 return (SNMP_ERR_NOT_WRITEABLE); 231 232 case SNMP_OP_ROLLBACK: 233 case SNMP_OP_COMMIT: 234 default: 235 abort(); 236 } 237 238 switch (value->var.subs[sub - 1]) { 239 240 case LEAF_udpLocalAddress: 241 value->v.ipaddress[0] = udpoids[i].index.subs[0]; 242 value->v.ipaddress[1] = udpoids[i].index.subs[1]; 243 value->v.ipaddress[2] = udpoids[i].index.subs[2]; 244 value->v.ipaddress[3] = udpoids[i].index.subs[3]; 245 break; 246 247 case LEAF_udpLocalPort: 248 value->v.integer = udpoids[i].index.subs[4]; 249 break; 250 251 } 252 return (SNMP_ERR_NOERROR); 253} 254