1 /* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 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 AUTHOR 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 AUTHOR 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 * $Begemot: bsnmp/snmp_mibII/mibII_udp.c,v 1.7 2005/05/23 09:03:42 brandt_h Exp $ 30 * 31 * udp 32 */ 33 #include "mibII.h" 34 #include "mibII_oid.h" 35 #include <sys/socketvar.h> 36 #include <netinet/in_pcb.h> 37 #include <netinet/udp.h> 38 #include <netinet/ip_var.h> 39 #include <netinet/udp_var.h> 40 41 struct udp_index { 42 struct asn_oid index; 43 struct xinpcb *inp; 44 }; 45 46 static uint64_t udp_tick; 47 static struct udpstat udpstat; 48 static struct xinpgen *xinpgen; 49 static size_t xinpgen_len; 50 static u_int udp_total; 51 52 static u_int oidnum; 53 static struct udp_index *udpoids; 54 55 static int 56 udp_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 64 static int 65 fetch_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 150 int 151 op_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 200 int 201 op_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