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