1 /* 2 * Copyright (c) 2001-2002 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_ipaddr.c,v 1.10 2005/10/04 11:21:35 brandt_h Exp $ 30 * 31 * IP address table. This table is writeable! 32 * 33 * Writing to this table will add a new IP address to the interface. 34 * An address can be deleted with writing the interface index 0. 35 */ 36 #include "mibII.h" 37 #include "mibII_oid.h" 38 39 static const struct asn_oid 40 oid_ipAddrTable = OIDX_ipAddrTable; 41 42 /* 43 * Be careful not to hold any pointers during the SET processing - the 44 * interface and address lists can be relocated at any time. 45 */ 46 struct update { 47 struct snmp_dependency dep; 48 49 uint32_t set; 50 struct in_addr addr; 51 struct in_addr mask; 52 int bcast; 53 u_int ifindex; 54 55 uint32_t rb; 56 struct in_addr rb_mask; 57 struct in_addr rb_bcast; 58 }; 59 #define UPD_IFINDEX 0x0001 60 #define UPD_MASK 0x0002 61 #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 */ 69 static int 70 create(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 */ 104 static int 105 modify(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 */ 144 static int 145 destroy(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 */ 157 static int 158 update_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 */ 219 int 220 op_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