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.9 2004/08/06 08:47:02 brandt 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 bcast.s_addr |= htonl(0xffffffff & ~ntohl(upd->mask.s_addr)); 89 90 if ((ifa = mib_create_ifa(upd->ifindex, upd->addr, upd->mask, bcast)) == NULL) 91 return (SNMP_ERR_GENERR); 92 93 upd->rb |= RB_CREATE; 94 return (SNMP_ERR_NOERROR); 95 } 96 97 /* 98 * Modify the netmask or broadcast address. The ifindex cannot be 99 * changed (obviously). 100 */ 101 static int 102 modify(struct update *upd, struct mibifa *ifa) 103 { 104 struct mibif *ifp; 105 106 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) 107 return (SNMP_ERR_WRONG_VALUE); 108 if ((upd->set & UPD_IFINDEX) && upd->ifindex != ifa->ifindex) 109 return (SNMP_ERR_INCONS_VALUE); 110 111 upd->rb_mask = ifa->inmask; 112 upd->rb_bcast = ifa->inbcast; 113 if (((upd->set & UPD_MASK) && upd->mask.s_addr != ifa->inmask.s_addr) || 114 (upd->set & UPD_BCAST)) { 115 if (upd->set & UPD_MASK) 116 ifa->inmask = upd->mask; 117 if (upd->set & UPD_BCAST) { 118 ifa->inbcast.s_addr = ifa->inaddr.s_addr 119 & ifa->inmask.s_addr; 120 if (upd->bcast) 121 ifa->inbcast.s_addr |= 0xffffffff 122 & ~ifa->inmask.s_addr; 123 } 124 if (mib_modify_ifa(ifa)) { 125 syslog(LOG_ERR, "set netmask/bcast: %m"); 126 ifa->inmask = upd->rb_mask; 127 ifa->inbcast = upd->rb_bcast; 128 mib_unmodify_ifa(ifa); 129 return (SNMP_ERR_GENERR); 130 } 131 upd->rb |= RB_MODIFY; 132 } 133 return (SNMP_ERR_NOERROR); 134 } 135 136 /* 137 * Destroy the given row in the table. We remove the address from the 138 * system, but keep the structure around for the COMMIT. It's deleted 139 * only in the FINISH operation. 140 */ 141 static int 142 destroy(struct snmp_context *ctx __unused, struct update *upd, 143 struct mibifa *ifa) 144 { 145 if (mib_destroy_ifa(ifa)) 146 return (SNMP_ERR_GENERR); 147 upd->rb |= RB_DESTROY; 148 return (SNMP_ERR_NOERROR); 149 } 150 151 /* 152 * This function is called to commit/rollback a SET on an IpAddrEntry 153 */ 154 static int 155 update_func(struct snmp_context *ctx, struct snmp_dependency *dep, 156 enum snmp_depop op) 157 { 158 struct update *upd = (struct update *)dep; 159 struct mibifa *ifa; 160 161 switch (op) { 162 163 case SNMP_DEPOP_COMMIT: 164 if ((ifa = mib_find_ifa(upd->addr)) == NULL) { 165 /* non existing entry - must have ifindex */ 166 if (!(upd->set & UPD_IFINDEX)) 167 return (SNMP_ERR_INCONS_NAME); 168 return (create(upd)); 169 } 170 /* existing entry */ 171 if ((upd->set & UPD_IFINDEX) && upd->ifindex == 0) { 172 /* delete */ 173 return (destroy(ctx, upd, ifa)); 174 } 175 /* modify entry */ 176 return (modify(upd, ifa)); 177 178 case SNMP_DEPOP_ROLLBACK: 179 if ((ifa = mib_find_ifa(upd->addr)) == NULL) { 180 /* ups */ 181 mib_iflist_bad = 1; 182 return (SNMP_ERR_NOERROR); 183 } 184 if (upd->rb & RB_CREATE) { 185 mib_uncreate_ifa(ifa); 186 return (SNMP_ERR_NOERROR); 187 } 188 if (upd->rb & RB_DESTROY) { 189 mib_undestroy_ifa(ifa); 190 return (SNMP_ERR_NOERROR); 191 } 192 if (upd->rb & RB_MODIFY) { 193 ifa->inmask = upd->rb_mask; 194 ifa->inbcast = upd->rb_bcast; 195 mib_unmodify_ifa(ifa); 196 return (SNMP_ERR_NOERROR); 197 } 198 return (SNMP_ERR_NOERROR); 199 200 case SNMP_DEPOP_FINISH: 201 if ((upd->rb & RB_DESTROY) && 202 (ifa = mib_find_ifa(upd->addr)) != NULL && 203 (ifa->flags & MIBIFA_DESTROYED)) { 204 TAILQ_REMOVE(&mibifa_list, ifa, link); 205 free(ifa); 206 } 207 return (SNMP_ERR_NOERROR); 208 } 209 abort(); 210 } 211 212 /**********************************************************************/ 213 /* 214 * ACTION 215 */ 216 int 217 op_ipaddr(struct snmp_context *ctx, struct snmp_value *value, 218 u_int sub, u_int iidx, enum snmp_op op) 219 { 220 asn_subid_t which; 221 struct mibifa *ifa; 222 struct update *upd; 223 struct asn_oid idx; 224 u_char ipaddr[4]; 225 226 which = value->var.subs[sub - 1]; 227 228 ifa = NULL; 229 230 switch (op) { 231 232 case SNMP_OP_GETNEXT: 233 if ((ifa = NEXT_OBJECT_OID(&mibifa_list, &value->var, sub)) == NULL) 234 return (SNMP_ERR_NOSUCHNAME); 235 index_append(&value->var, sub, &ifa->index); 236 break; 237 238 case SNMP_OP_GET: 239 if ((ifa = FIND_OBJECT_OID(&mibifa_list, &value->var, sub)) == NULL) 240 return (SNMP_ERR_NOSUCHNAME); 241 break; 242 243 case SNMP_OP_SET: 244 if (index_decode(&value->var, sub, iidx, ipaddr)) 245 return (SNMP_ERR_NO_CREATION); 246 ifa = FIND_OBJECT_OID(&mibifa_list, &value->var, sub); 247 idx.len = 4; 248 idx.subs[0] = ipaddr[0]; 249 idx.subs[1] = ipaddr[1]; 250 idx.subs[2] = ipaddr[2]; 251 idx.subs[3] = ipaddr[3]; 252 253 if ((upd = (struct update *)snmp_dep_lookup(ctx, 254 &oid_ipAddrTable, &idx, sizeof(*upd), update_func)) == NULL) 255 return (SNMP_ERR_RES_UNAVAIL); 256 257 upd->addr.s_addr = htonl((ipaddr[0] << 24) | (ipaddr[1] << 16) | 258 (ipaddr[2] << 8) | (ipaddr[3] << 0)); 259 260 switch (which) { 261 262 case LEAF_ipAdEntIfIndex: 263 if (upd->set & UPD_IFINDEX) 264 return (SNMP_ERR_INCONS_VALUE); 265 if (value->v.integer < 0 || 266 value->v.integer > 0x07fffffff) 267 return (SNMP_ERR_WRONG_VALUE); 268 if (ifa != NULL) { 269 if (ifa->ifindex != (u_int)value->v.integer && 270 value->v.integer != 0) 271 return (SNMP_ERR_INCONS_VALUE); 272 } 273 upd->set |= UPD_IFINDEX; 274 upd->ifindex = (u_int)value->v.integer; 275 break; 276 277 case LEAF_ipAdEntNetMask: 278 if (upd->set & UPD_MASK) 279 return (SNMP_ERR_INCONS_VALUE); 280 upd->mask.s_addr = htonl((value->v.ipaddress[0] << 24) 281 | (value->v.ipaddress[1] << 16) 282 | (value->v.ipaddress[2] << 8) 283 | (value->v.ipaddress[3] << 0)); 284 upd->set |= UPD_MASK; 285 break; 286 287 case LEAF_ipAdEntBcastAddr: 288 if (upd->set & UPD_BCAST) 289 return (SNMP_ERR_INCONS_VALUE); 290 if (value->v.integer != 0 && value->v.integer != 1) 291 return (SNMP_ERR_WRONG_VALUE); 292 upd->bcast = value->v.integer; 293 upd->set |= UPD_BCAST; 294 break; 295 296 } 297 return (SNMP_ERR_NOERROR); 298 299 case SNMP_OP_ROLLBACK: 300 case SNMP_OP_COMMIT: 301 return (SNMP_ERR_NOERROR); 302 } 303 304 switch (which) { 305 306 case LEAF_ipAdEntAddr: 307 value->v.ipaddress[0] = ifa->index.subs[0]; 308 value->v.ipaddress[1] = ifa->index.subs[1]; 309 value->v.ipaddress[2] = ifa->index.subs[2]; 310 value->v.ipaddress[3] = ifa->index.subs[3]; 311 break; 312 313 case LEAF_ipAdEntIfIndex: 314 if (ifa->flags & MIBIFA_DESTROYED) 315 value->v.integer = 0; 316 else 317 value->v.integer = ifa->ifindex; 318 break; 319 320 case LEAF_ipAdEntNetMask: 321 value->v.ipaddress[0] = (ntohl(ifa->inmask.s_addr) >> 24) & 0xff; 322 value->v.ipaddress[1] = (ntohl(ifa->inmask.s_addr) >> 16) & 0xff; 323 value->v.ipaddress[2] = (ntohl(ifa->inmask.s_addr) >> 8) & 0xff; 324 value->v.ipaddress[3] = (ntohl(ifa->inmask.s_addr) >> 0) & 0xff; 325 break; 326 327 case LEAF_ipAdEntBcastAddr: 328 value->v.integer = ntohl(ifa->inbcast.s_addr) & 1; 329 break; 330 331 332 case LEAF_ipAdEntReasmMaxSize: 333 value->v.integer = 65535; 334 break; 335 } 336 return (SNMP_ERR_NOERROR); 337 } 338