10SN/A/* 2553SN/A * Copyright (c) 2001-2002 30SN/A * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 40SN/A * All rights reserved. 50SN/A * 60SN/A * Author: Harti Brandt <harti@freebsd.org> 7553SN/A * 80SN/A * Redistribution and use in source and binary forms, with or without 9553SN/A * modification, are permitted provided that the following conditions 100SN/A * are met: 110SN/A * 1. Redistributions of source code must retain the above copyright 120SN/A * notice, this list of conditions and the following disclaimer. 130SN/A * 2. Redistributions in binary form must reproduce the above copyright 140SN/A * notice, this list of conditions and the following disclaimer in the 150SN/A * documentation and/or other materials provided with the distribution. 160SN/A * 170SN/A * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 180SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 190SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 200SN/A * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21553SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22553SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23553SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 240SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 250SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 260SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 270SN/A * SUCH DAMAGE. 28415SN/A * 290SN/A * $Begemot: bsnmp/snmp_mibII/mibII_ipaddr.c,v 1.10 2005/10/04 11:21:35 brandt_h Exp $ 300SN/A * 31415SN/A * IP address table. This table is writeable! 320SN/A * 33580SN/A * Writing to this table will add a new IP address to the interface. 34580SN/A * An address can be deleted with writing the interface index 0. 35415SN/A */ 36415SN/A#include "mibII.h" 370SN/A#include "mibII_oid.h" 38415SN/A 39415SN/Astatic const struct asn_oid 40415SN/A oid_ipAddrTable = OIDX_ipAddrTable; 41415SN/A 42415SN/A/* 430SN/A * Be careful not to hold any pointers during the SET processing - the 44415SN/A * interface and address lists can be relocated at any time. 45415SN/A */ 46415SN/Astruct update { 470SN/A struct snmp_dependency dep; 480SN/A 49415SN/A uint32_t set; 50415SN/A struct in_addr addr; 51415SN/A struct in_addr mask; 52415SN/A int bcast; 53415SN/A u_int ifindex; 54415SN/A 55415SN/A uint32_t rb; 56415SN/A struct in_addr rb_mask; 57415SN/A struct in_addr rb_bcast; 58415SN/A}; 59415SN/A#define UPD_IFINDEX 0x0001 60415SN/A#define UPD_MASK 0x0002 610SN/A#define UPD_BCAST 0x0004 62#define RB_CREATE 0x0001 63#define RB_DESTROY 0x0002 64#define RB_MODIFY 0x0004 65 66/* 67 * Create a new interface address 68 */ 69static int 70create(struct update *upd) 71{ 72 struct in_addr bcast; 73 struct mibifa *ifa; 74 75 if (!(upd->set & UPD_MASK)) { 76 if (IN_CLASSA(ntohl(upd->addr.s_addr))) 77 upd->mask.s_addr = htonl(IN_CLASSA_NET); 78 else if (IN_CLASSB(ntohl(upd->addr.s_addr))) 79 upd->mask.s_addr = htonl(IN_CLASSB_NET); 80 else if (IN_CLASSC(ntohl(upd->addr.s_addr))) 81 upd->mask.s_addr = htonl(IN_CLASSC_NET); 82 else 83 upd->mask.s_addr = 0xffffffff; 84 } 85 86 bcast.s_addr = upd->addr.s_addr & upd->mask.s_addr; 87 if (!(upd->set & UPD_BCAST) || upd->bcast) { 88 uint32_t tmp = ~ntohl(upd->mask.s_addr); 89 bcast.s_addr |= htonl(0xffffffff & ~tmp); 90 } 91 92 if ((ifa = mib_create_ifa(upd->ifindex, upd->addr, upd->mask, bcast)) 93 == NULL) 94 return (SNMP_ERR_GENERR); 95 96 upd->rb |= RB_CREATE; 97 return (SNMP_ERR_NOERROR); 98} 99 100/* 101 * Modify the netmask or broadcast address. The ifindex cannot be 102 * changed (obviously). 103 */ 104static int 105modify(struct update *upd, struct mibifa *ifa) 106{ 107 struct mibif *ifp; 108 109 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) 110 return (SNMP_ERR_WRONG_VALUE); 111 if ((upd->set & UPD_IFINDEX) && upd->ifindex != ifa->ifindex) 112 return (SNMP_ERR_INCONS_VALUE); 113 114 upd->rb_mask = ifa->inmask; 115 upd->rb_bcast = ifa->inbcast; 116 if (((upd->set & UPD_MASK) && upd->mask.s_addr != ifa->inmask.s_addr) || 117 (upd->set & UPD_BCAST)) { 118 if (upd->set & UPD_MASK) 119 ifa->inmask = upd->mask; 120 if (upd->set & UPD_BCAST) { 121 ifa->inbcast.s_addr = ifa->inaddr.s_addr 122 & ifa->inmask.s_addr; 123 if (upd->bcast) 124 ifa->inbcast.s_addr |= 0xffffffff 125 & ~ifa->inmask.s_addr; 126 } 127 if (mib_modify_ifa(ifa)) { 128 syslog(LOG_ERR, "set netmask/bcast: %m"); 129 ifa->inmask = upd->rb_mask; 130 ifa->inbcast = upd->rb_bcast; 131 mib_unmodify_ifa(ifa); 132 return (SNMP_ERR_GENERR); 133 } 134 upd->rb |= RB_MODIFY; 135 } 136 return (SNMP_ERR_NOERROR); 137} 138 139/* 140 * Destroy the given row in the table. We remove the address from the 141 * system, but keep the structure around for the COMMIT. It's deleted 142 * only in the FINISH operation. 143 */ 144static int 145destroy(struct snmp_context *ctx __unused, struct update *upd, 146 struct mibifa *ifa) 147{ 148 if (mib_destroy_ifa(ifa)) 149 return (SNMP_ERR_GENERR); 150 upd->rb |= RB_DESTROY; 151 return (SNMP_ERR_NOERROR); 152} 153 154/* 155 * This function is called to commit/rollback a SET on an IpAddrEntry 156 */ 157static int 158update_func(struct snmp_context *ctx, struct snmp_dependency *dep, 159 enum snmp_depop op) 160{ 161 struct update *upd = (struct update *)dep; 162 struct mibifa *ifa; 163 164 switch (op) { 165 166 case SNMP_DEPOP_COMMIT: 167 if ((ifa = mib_find_ifa(upd->addr)) == NULL) { 168 /* non existing entry - must have ifindex */ 169 if (!(upd->set & UPD_IFINDEX)) 170 return (SNMP_ERR_INCONS_NAME); 171 return (create(upd)); 172 } 173 /* existing entry */ 174 if ((upd->set & UPD_IFINDEX) && upd->ifindex == 0) { 175 /* delete */ 176 return (destroy(ctx, upd, ifa)); 177 } 178 /* modify entry */ 179 return (modify(upd, ifa)); 180 181 case SNMP_DEPOP_ROLLBACK: 182 if ((ifa = mib_find_ifa(upd->addr)) == NULL) { 183 /* ups */ 184 mib_iflist_bad = 1; 185 return (SNMP_ERR_NOERROR); 186 } 187 if (upd->rb & RB_CREATE) { 188 mib_uncreate_ifa(ifa); 189 return (SNMP_ERR_NOERROR); 190 } 191 if (upd->rb & RB_DESTROY) { 192 mib_undestroy_ifa(ifa); 193 return (SNMP_ERR_NOERROR); 194 } 195 if (upd->rb & RB_MODIFY) { 196 ifa->inmask = upd->rb_mask; 197 ifa->inbcast = upd->rb_bcast; 198 mib_unmodify_ifa(ifa); 199 return (SNMP_ERR_NOERROR); 200 } 201 return (SNMP_ERR_NOERROR); 202 203 case SNMP_DEPOP_FINISH: 204 if ((upd->rb & RB_DESTROY) && 205 (ifa = mib_find_ifa(upd->addr)) != NULL && 206 (ifa->flags & MIBIFA_DESTROYED)) { 207 TAILQ_REMOVE(&mibifa_list, ifa, link); 208 free(ifa); 209 } 210 return (SNMP_ERR_NOERROR); 211 } 212 abort(); 213} 214 215/**********************************************************************/ 216/* 217 * ACTION 218 */ 219int 220op_ipaddr(struct snmp_context *ctx, struct snmp_value *value, 221 u_int sub, u_int iidx, enum snmp_op op) 222{ 223 asn_subid_t which; 224 struct mibifa *ifa; 225 struct update *upd; 226 struct asn_oid idx; 227 u_char ipaddr[4]; 228 229 which = value->var.subs[sub - 1]; 230 231 ifa = NULL; 232 233 switch (op) { 234 235 case SNMP_OP_GETNEXT: 236 if ((ifa = NEXT_OBJECT_OID(&mibifa_list, &value->var, sub)) == NULL) 237 return (SNMP_ERR_NOSUCHNAME); 238 index_append(&value->var, sub, &ifa->index); 239 break; 240 241 case SNMP_OP_GET: 242 if ((ifa = FIND_OBJECT_OID(&mibifa_list, &value->var, sub)) == NULL) 243 return (SNMP_ERR_NOSUCHNAME); 244 break; 245 246 case SNMP_OP_SET: 247 if (index_decode(&value->var, sub, iidx, ipaddr)) 248 return (SNMP_ERR_NO_CREATION); 249 ifa = FIND_OBJECT_OID(&mibifa_list, &value->var, sub); 250 idx.len = 4; 251 idx.subs[0] = ipaddr[0]; 252 idx.subs[1] = ipaddr[1]; 253 idx.subs[2] = ipaddr[2]; 254 idx.subs[3] = ipaddr[3]; 255 256 if ((upd = (struct update *)snmp_dep_lookup(ctx, 257 &oid_ipAddrTable, &idx, sizeof(*upd), update_func)) == NULL) 258 return (SNMP_ERR_RES_UNAVAIL); 259 260 upd->addr.s_addr = htonl((ipaddr[0] << 24) | (ipaddr[1] << 16) | 261 (ipaddr[2] << 8) | (ipaddr[3] << 0)); 262 263 switch (which) { 264 265 case LEAF_ipAdEntIfIndex: 266 if (upd->set & UPD_IFINDEX) 267 return (SNMP_ERR_INCONS_VALUE); 268 if (value->v.integer < 0 || 269 value->v.integer > 0x07fffffff) 270 return (SNMP_ERR_WRONG_VALUE); 271 if (ifa != NULL) { 272 if (ifa->ifindex != (u_int)value->v.integer && 273 value->v.integer != 0) 274 return (SNMP_ERR_INCONS_VALUE); 275 } 276 upd->set |= UPD_IFINDEX; 277 upd->ifindex = (u_int)value->v.integer; 278 break; 279 280 case LEAF_ipAdEntNetMask: 281 if (upd->set & UPD_MASK) 282 return (SNMP_ERR_INCONS_VALUE); 283 upd->mask.s_addr = htonl((value->v.ipaddress[0] << 24) 284 | (value->v.ipaddress[1] << 16) 285 | (value->v.ipaddress[2] << 8) 286 | (value->v.ipaddress[3] << 0)); 287 upd->set |= UPD_MASK; 288 break; 289 290 case LEAF_ipAdEntBcastAddr: 291 if (upd->set & UPD_BCAST) 292 return (SNMP_ERR_INCONS_VALUE); 293 if (value->v.integer != 0 && value->v.integer != 1) 294 return (SNMP_ERR_WRONG_VALUE); 295 upd->bcast = value->v.integer; 296 upd->set |= UPD_BCAST; 297 break; 298 299 } 300 return (SNMP_ERR_NOERROR); 301 302 case SNMP_OP_ROLLBACK: 303 case SNMP_OP_COMMIT: 304 return (SNMP_ERR_NOERROR); 305 } 306 307 switch (which) { 308 309 case LEAF_ipAdEntAddr: 310 value->v.ipaddress[0] = ifa->index.subs[0]; 311 value->v.ipaddress[1] = ifa->index.subs[1]; 312 value->v.ipaddress[2] = ifa->index.subs[2]; 313 value->v.ipaddress[3] = ifa->index.subs[3]; 314 break; 315 316 case LEAF_ipAdEntIfIndex: 317 if (ifa->flags & MIBIFA_DESTROYED) 318 value->v.integer = 0; 319 else 320 value->v.integer = ifa->ifindex; 321 break; 322 323 case LEAF_ipAdEntNetMask: 324 value->v.ipaddress[0] = (ntohl(ifa->inmask.s_addr) >> 24) & 0xff; 325 value->v.ipaddress[1] = (ntohl(ifa->inmask.s_addr) >> 16) & 0xff; 326 value->v.ipaddress[2] = (ntohl(ifa->inmask.s_addr) >> 8) & 0xff; 327 value->v.ipaddress[3] = (ntohl(ifa->inmask.s_addr) >> 0) & 0xff; 328 break; 329 330 case LEAF_ipAdEntBcastAddr: 331 value->v.integer = ntohl(ifa->inbcast.s_addr) & 1; 332 break; 333 334 335 case LEAF_ipAdEntReasmMaxSize: 336 value->v.integer = 65535; 337 break; 338 } 339 return (SNMP_ERR_NOERROR); 340} 341