1 /* $OpenBSD: interface.c,v 1.6 2008/12/17 14:19:39 michele Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> 5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/ioctl.h> 23 #include <sys/time.h> 24 #include <sys/socket.h> 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 #include <net/if.h> 28 #include <net/if_types.h> 29 #include <ctype.h> 30 #include <err.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <string.h> 35 #include <event.h> 36 37 #include "ripd.h" 38 #include "log.h" 39 #include "rip.h" 40 #include "rde.h" 41 #include "ripe.h" 42 43 extern struct ripd_conf *conf; 44 45 int if_act_start(struct iface *); 46 int if_act_reset(struct iface *); 47 48 struct { 49 int state; 50 enum iface_event event; 51 enum iface_action action; 52 int new_state; 53 } iface_fsm[] = { 54 /* current state event that happened action to take resulting state */ 55 {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0}, 56 {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 57 {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 58 }; 59 60 const char * const if_action_names[] = { 61 "NOTHING", 62 "START", 63 "RESET" 64 }; 65 66 static const char * const if_event_names[] = { 67 "NOTHING", 68 "UP", 69 "DOWN", 70 }; 71 72 void 73 if_init(struct ripd_conf *xconf, struct iface *iface) 74 { 75 /* XXX as in ospfd I would like to kill that. This is a design error */ 76 iface->fd = xconf->rip_socket; 77 78 ripe_demote_iface(iface, 0); 79 } 80 81 int 82 if_fsm(struct iface *iface, enum iface_event event) 83 { 84 int old_state; 85 int new_state = 0; 86 int i, ret = 0; 87 88 old_state = iface->state; 89 90 for (i = 0; iface_fsm[i].state != -1; i++) 91 if ((iface_fsm[i].state & old_state) && 92 (iface_fsm[i].event == event)) { 93 new_state = iface_fsm[i].new_state; 94 break; 95 } 96 97 if (iface_fsm[i].state == -1) { 98 /* event outside of the defined fsm, ignore it. */ 99 log_debug("if_fsm: interface %s, " 100 "event '%s' not expected in state '%s'", iface->name, 101 if_event_name(event), if_state_name(old_state)); 102 return (0); 103 } 104 105 switch (iface_fsm[i].action) { 106 case IF_ACT_STRT: 107 ret = if_act_start(iface); 108 break; 109 case IF_ACT_RST: 110 ret = if_act_reset(iface); 111 break; 112 case IF_ACT_NOTHING: 113 /* do nothing */ 114 break; 115 } 116 117 if (ret) { 118 log_debug("if_fsm: error changing state for interface %s, " 119 "event '%s', state '%s'", iface->name, if_event_name(event), 120 if_state_name(old_state)); 121 return (0); 122 } 123 124 if (new_state != 0) 125 iface->state = new_state; 126 127 if (old_state == IF_STA_ACTIVE && iface->state == IF_STA_DOWN) 128 ripe_demote_iface(iface, 0); 129 if (old_state & IF_STA_DOWN && iface->state == IF_STA_ACTIVE) 130 ripe_demote_iface(iface, 1); 131 132 log_debug("if_fsm: event '%s' resulted in action '%s' and changing " 133 "state for interface %s from '%s' to '%s'", 134 if_event_name(event), if_action_name(iface_fsm[i].action), 135 iface->name, if_state_name(old_state), if_state_name(iface->state)); 136 137 return (ret); 138 } 139 140 struct iface * 141 if_find_index(u_short ifindex) 142 { 143 struct iface *iface; 144 145 LIST_FOREACH(iface, &conf->iface_list, entry) { 146 if (iface->ifindex == ifindex) 147 return (iface); 148 } 149 150 return (NULL); 151 } 152 153 154 /* actions */ 155 int 156 if_act_start(struct iface *iface) 157 { 158 struct in_addr addr; 159 struct timeval now; 160 161 if (iface->passive) { 162 log_debug("if_act_start: cannot start passive interface %s", 163 iface->name); 164 return (0); 165 } 166 167 if (!((iface->flags & IFF_UP) && 168 (LINK_STATE_IS_UP(iface->linkstate) || 169 (iface->linkstate == LINK_STATE_UNKNOWN && 170 iface->media_type != IFT_CARP)))) { 171 log_debug("if_act_start: interface %s link down", 172 iface->name); 173 return (0); 174 } 175 176 gettimeofday(&now, NULL); 177 iface->uptime = now.tv_sec; 178 179 switch (iface->type) { 180 case IF_TYPE_POINTOPOINT: 181 case IF_TYPE_BROADCAST: 182 inet_aton(ALL_RIP_ROUTERS, &addr); 183 if (if_join_group(iface, &addr)) { 184 log_warn("if_act_start: error joining group %s, " 185 "interface %s", inet_ntoa(addr), iface->name); 186 return (-1); 187 } 188 189 iface->state = IF_STA_ACTIVE; 190 break; 191 default: 192 fatalx("if_act_start: unknown interface type"); 193 } 194 195 return (0); 196 } 197 198 int 199 if_act_reset(struct iface *iface) 200 { 201 struct nbr *nbr = NULL; 202 struct in_addr addr; 203 204 if (iface->passive) 205 return (0); 206 207 switch (iface->type) { 208 case IF_TYPE_POINTOPOINT: 209 case IF_TYPE_BROADCAST: 210 inet_aton(ALL_RIP_ROUTERS, &addr); 211 if (if_leave_group(iface, &addr)) { 212 log_warn("if_act_reset: error leaving group %s, " 213 "interface %s", inet_ntoa(addr), iface->name); 214 } 215 break; 216 default: 217 fatalx("if_act_reset: unknown interface type"); 218 } 219 220 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 221 if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) { 222 log_debug("if_act_reset: error killing neighbor %s", 223 inet_ntoa(nbr->id)); 224 } 225 } 226 227 return (0); 228 } 229 230 const char * 231 if_event_name(int event) 232 { 233 return (if_event_names[event]); 234 } 235 236 const char * 237 if_action_name(int action) 238 { 239 return (if_action_names[action]); 240 } 241 242 /* misc */ 243 int 244 if_set_mcast_ttl(int fd, u_int8_t ttl) 245 { 246 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 247 (char *)&ttl, sizeof(ttl)) < 0) { 248 log_warn("if_set_mcast_ttl: error setting " 249 "IP_MULTICAST_TTL to %d", ttl); 250 return (-1); 251 } 252 253 return (0); 254 } 255 256 int 257 if_set_opt(int fd) 258 { 259 int yes = 1; 260 261 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &yes, 262 sizeof(int)) < 0) { 263 log_warn("if_set_opt: error setting IP_RECVIF"); 264 return (-1); 265 } 266 267 return (0); 268 } 269 270 int 271 if_set_tos(int fd, int tos) 272 { 273 if (setsockopt(fd, IPPROTO_IP, IP_TOS, 274 (int *)&tos, sizeof(tos)) < 0) { 275 log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos); 276 return (-1); 277 } 278 279 return (0); 280 } 281 282 int 283 if_set_mcast(struct iface *iface) 284 { 285 switch (iface->type) { 286 case IF_TYPE_POINTOPOINT: 287 case IF_TYPE_BROADCAST: 288 if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF, 289 &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) { 290 log_debug("if_set_mcast: error setting " 291 "IP_MULTICAST_IF, interface %s", iface->name); 292 return (-1); 293 } 294 break; 295 default: 296 fatalx("if_set_mcast: unknown interface type"); 297 } 298 299 return (0); 300 } 301 302 int 303 if_set_mcast_loop(int fd) 304 { 305 u_int8_t loop = 0; 306 307 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 308 (char *)&loop, sizeof(loop)) < 0) { 309 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 310 return (-1); 311 } 312 313 return (0); 314 } 315 316 void 317 if_set_recvbuf(int fd) 318 { 319 int bsize; 320 321 bsize = 65535; 322 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 323 sizeof(bsize)) == -1) 324 bsize /= 2; 325 } 326 327 int 328 if_join_group(struct iface *iface, struct in_addr *addr) 329 { 330 struct ip_mreq mreq; 331 332 switch (iface->type) { 333 case IF_TYPE_POINTOPOINT: 334 case IF_TYPE_BROADCAST: 335 mreq.imr_multiaddr.s_addr = addr->s_addr; 336 mreq.imr_interface.s_addr = iface->addr.s_addr; 337 338 if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 339 (void *)&mreq, sizeof(mreq)) < 0) 340 return (-1); 341 break; 342 default: 343 fatalx("if_join_group: unknown interface type"); 344 } 345 346 return (0); 347 } 348 349 int 350 if_leave_group(struct iface *iface, struct in_addr *addr) 351 { 352 struct ip_mreq mreq; 353 354 switch (iface->type) { 355 case IF_TYPE_POINTOPOINT: 356 case IF_TYPE_BROADCAST: 357 mreq.imr_multiaddr.s_addr = addr->s_addr; 358 mreq.imr_interface.s_addr = iface->addr.s_addr; 359 360 if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 361 (void *)&mreq, sizeof(mreq)) < 0) 362 return (-1); 363 break; 364 default: 365 fatalx("if_leave_group: unknown interface type"); 366 } 367 368 return (0); 369 } 370 371 struct iface * 372 if_new(struct kif *kif) 373 { 374 struct sockaddr_in *sain; 375 struct iface *iface; 376 struct ifreq *ifr; 377 int s; 378 379 if ((iface = calloc(1, sizeof(*iface))) == NULL) 380 err(1, "if_new: calloc"); 381 382 iface->state = IF_STA_DOWN; 383 384 LIST_INIT(&iface->nbr_list); 385 TAILQ_INIT(&iface->rp_list); 386 TAILQ_INIT(&iface->rq_list); 387 388 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 389 390 if ((ifr = calloc(1, sizeof(*ifr))) == NULL) 391 err(1, "if_new: calloc"); 392 393 /* set up ifreq */ 394 strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name)); 395 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 396 err(1, "if_new: socket"); 397 398 /* get type */ 399 if (kif->flags & IFF_POINTOPOINT) 400 iface->type = IF_TYPE_POINTOPOINT; 401 if (kif->flags & IFF_BROADCAST && 402 kif->flags & IFF_MULTICAST) 403 iface->type = IF_TYPE_BROADCAST; 404 if (kif->flags & IFF_LOOPBACK) { 405 iface->type = IF_TYPE_POINTOPOINT; 406 /* XXX protect loopback from sending packets over lo? */ 407 } 408 409 /* get mtu, index and flags */ 410 iface->mtu = kif->mtu; 411 iface->ifindex = kif->ifindex; 412 iface->flags = kif->flags; 413 iface->linkstate = kif->link_state; 414 iface->media_type = kif->media_type; 415 iface->baudrate = kif->baudrate; 416 417 /* get address */ 418 if (ioctl(s, SIOCGIFADDR, ifr) < 0) 419 err(1, "if_new: cannot get address"); 420 sain = (struct sockaddr_in *)&ifr->ifr_addr; 421 iface->addr = sain->sin_addr; 422 423 /* get mask */ 424 if (ioctl(s, SIOCGIFNETMASK, ifr) < 0) 425 err(1, "if_new: cannot get mask"); 426 sain = (struct sockaddr_in *)&ifr->ifr_addr; 427 iface->mask = sain->sin_addr; 428 429 /* get p2p dst address */ 430 if (kif->flags & IFF_POINTOPOINT) { 431 if (ioctl(s, SIOCGIFDSTADDR, ifr) < 0) 432 err(1, "if_new: cannot get dst addr"); 433 sain = (struct sockaddr_in *)&ifr->ifr_addr; 434 iface->dst = sain->sin_addr; 435 } 436 437 free(ifr); 438 close(s); 439 440 return (iface); 441 } 442 443 void 444 if_del(struct iface *iface) 445 { 446 struct nbr *nbr; 447 448 log_debug("if_del: interface %s", iface->name); 449 450 /* revert the demotion when the interface is deleted */ 451 if (iface->state == IF_STA_DOWN) 452 ripe_demote_iface(iface, 1); 453 454 /* clear lists etc */ 455 while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) 456 nbr_act_del(nbr); 457 458 /* XXX rq_list, rp_list */ 459 460 free(iface); 461 } 462 463 struct ctl_iface * 464 if_to_ctl(struct iface *iface) 465 { 466 static struct ctl_iface ictl; 467 struct timeval now; 468 469 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 470 memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); 471 memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); 472 473 ictl.ifindex = iface->ifindex; 474 ictl.state = iface->state; 475 ictl.mtu = iface->mtu; 476 477 ictl.baudrate = iface->baudrate; 478 ictl.flags = iface->flags; 479 ictl.metric = iface->cost; 480 ictl.type = iface->type; 481 ictl.linkstate = iface->linkstate; 482 ictl.passive = iface->passive; 483 ictl.mediatype = iface->media_type; 484 485 gettimeofday(&now, NULL); 486 487 if (iface->state != IF_STA_DOWN) { 488 ictl.uptime = now.tv_sec - iface->uptime; 489 } else 490 ictl.uptime = 0; 491 492 return (&ictl); 493 } 494