1 /* $OpenBSD: interface.c,v 1.2 2006/11/28 19:21:15 reyk 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 void if_keepalive_timer(int, short, void *); 48 49 struct { 50 int state; 51 enum iface_event event; 52 enum iface_action action; 53 int new_state; 54 } iface_fsm[] = { 55 /* current state event that happened action to take resulting state */ 56 {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0}, 57 {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 58 {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 59 }; 60 61 const char * const if_action_names[] = { 62 "NOTHING", 63 "START", 64 "RESET" 65 }; 66 67 static const char * const if_event_names[] = { 68 "NOTHING", 69 "UP", 70 "DOWN", 71 }; 72 73 void 74 if_init(struct ripd_conf *xconf, struct iface *iface) 75 { 76 /* XXX as in ospfd I would like to kill that. This is a design error */ 77 iface->fd = xconf->rip_socket; 78 } 79 80 int 81 if_fsm(struct iface *iface, enum iface_event event) 82 { 83 int old_state; 84 int new_state = 0; 85 int i, ret = 0; 86 87 old_state = iface->state; 88 89 for (i = 0; iface_fsm[i].state != -1; i++) 90 if ((iface_fsm[i].state & old_state) && 91 (iface_fsm[i].event == event)) { 92 new_state = iface_fsm[i].new_state; 93 break; 94 } 95 96 if (iface_fsm[i].state == -1) { 97 /* event outside of the defined fsm, ignore it. */ 98 log_debug("if_fsm: interface %s, " 99 "event '%s' not expected in state '%s'", iface->name, 100 if_event_name(event), if_state_name(old_state)); 101 return (0); 102 } 103 104 switch (iface_fsm[i].action) { 105 case IF_ACT_STRT: 106 ret = if_act_start(iface); 107 break; 108 case IF_ACT_RST: 109 ret = if_act_reset(iface); 110 break; 111 case IF_ACT_NOTHING: 112 /* do nothing */ 113 break; 114 } 115 116 if (ret) { 117 log_debug("if_fsm: error changing state for interface %s, " 118 "event '%s', state '%s'", iface->name, if_event_name(event), 119 if_state_name(old_state)); 120 return (0); 121 } 122 123 if (new_state != 0) 124 iface->state = new_state; 125 126 log_debug("if_fsm: event '%s' resulted in action '%s' and changing " 127 "state for interface %s from '%s' to '%s'", 128 if_event_name(event), if_action_name(iface_fsm[i].action), 129 iface->name, if_state_name(old_state), if_state_name(iface->state)); 130 131 return (ret); 132 } 133 134 struct iface * 135 if_find_index(u_short ifindex) 136 { 137 struct iface *iface; 138 139 LIST_FOREACH(iface, &conf->iface_list, entry) { 140 if (iface->ifindex == ifindex) 141 return (iface); 142 } 143 144 return (NULL); 145 } 146 147 148 /* actions */ 149 int 150 if_act_start(struct iface *iface) 151 { 152 struct in_addr addr; 153 struct timeval now; 154 155 if (iface->passive) { 156 log_debug("if_act_start: cannot start passive interface %s", 157 iface->name); 158 return (0); 159 } 160 161 if (!((iface->flags & IFF_UP) && 162 (LINK_STATE_IS_UP(iface->linkstate) || 163 (iface->linkstate == LINK_STATE_UNKNOWN && 164 iface->media_type != IFT_CARP)))) { 165 log_debug("if_act_start: interface %s link down", 166 iface->name); 167 return (0); 168 } 169 170 gettimeofday(&now, NULL); 171 iface->uptime = now.tv_sec; 172 173 switch (iface->type) { 174 case IF_TYPE_POINTOPOINT: 175 case IF_TYPE_BROADCAST: 176 inet_aton(ALL_RIP_ROUTERS, &addr); 177 if (if_join_group(iface, &addr)) { 178 log_warn("if_act_start: error joining group %s, " 179 "interface %s", inet_ntoa(addr), iface->name); 180 return (-1); 181 } 182 183 iface->state = IF_STA_ACTIVE; 184 break; 185 default: 186 fatalx("if_act_start: unknown interface type"); 187 } 188 189 return (0); 190 } 191 192 int 193 if_act_reset(struct iface *iface) 194 { 195 struct nbr *nbr = NULL; 196 struct in_addr addr; 197 198 if (iface->passive) 199 return (0); 200 201 switch (iface->type) { 202 case IF_TYPE_POINTOPOINT: 203 case IF_TYPE_BROADCAST: 204 inet_aton(ALL_RIP_ROUTERS, &addr); 205 if (if_leave_group(iface, &addr)) { 206 log_warn("if_act_reset: error leaving group %s, " 207 "interface %s", inet_ntoa(addr), iface->name); 208 } 209 break; 210 default: 211 fatalx("if_act_reset: unknown interface type"); 212 } 213 214 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 215 if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) { 216 log_debug("if_act_reset: error killing neighbor %s", 217 inet_ntoa(nbr->id)); 218 } 219 } 220 221 return (0); 222 } 223 224 const char * 225 if_event_name(int event) 226 { 227 return (if_event_names[event]); 228 } 229 230 const char * 231 if_action_name(int action) 232 { 233 return (if_action_names[action]); 234 } 235 236 /* misc */ 237 int 238 if_set_mcast_ttl(int fd, u_int8_t ttl) 239 { 240 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 241 (char *)&ttl, sizeof(ttl)) < 0) { 242 log_warn("if_set_mcast_ttl: error setting " 243 "IP_MULTICAST_TTL to %d", ttl); 244 return (-1); 245 } 246 247 return (0); 248 } 249 250 int 251 if_set_opt(int fd) 252 { 253 int yes = 1; 254 255 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &yes, 256 sizeof(int)) < 0) { 257 log_warn("if_set_opt: error setting IP_RECVIF"); 258 return (-1); 259 } 260 261 return (0); 262 } 263 264 int 265 if_set_tos(int fd, int tos) 266 { 267 if (setsockopt(fd, IPPROTO_IP, IP_TOS, 268 (int *)&tos, sizeof(tos)) < 0) { 269 log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos); 270 return (-1); 271 } 272 273 return (0); 274 } 275 276 int 277 if_set_mcast(struct iface *iface) 278 { 279 switch (iface->type) { 280 case IF_TYPE_POINTOPOINT: 281 case IF_TYPE_BROADCAST: 282 if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF, 283 &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) { 284 log_debug("if_set_mcast: error setting " 285 "IP_MULTICAST_IF, interface %s", iface->name); 286 return (-1); 287 } 288 break; 289 default: 290 fatalx("if_set_mcast: unknown interface type"); 291 } 292 293 return (0); 294 } 295 296 int 297 if_set_mcast_loop(int fd) 298 { 299 u_int8_t loop = 0; 300 301 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 302 (char *)&loop, sizeof(loop)) < 0) { 303 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 304 return (-1); 305 } 306 307 return (0); 308 } 309 310 void 311 if_set_recvbuf(int fd) 312 { 313 int bsize; 314 315 bsize = 65535; 316 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 317 sizeof(bsize)) == -1) 318 bsize /= 2; 319 } 320 321 int 322 if_join_group(struct iface *iface, struct in_addr *addr) 323 { 324 struct ip_mreq mreq; 325 326 switch (iface->type) { 327 case IF_TYPE_POINTOPOINT: 328 case IF_TYPE_BROADCAST: 329 mreq.imr_multiaddr.s_addr = addr->s_addr; 330 mreq.imr_interface.s_addr = iface->addr.s_addr; 331 332 if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 333 (void *)&mreq, sizeof(mreq)) < 0) 334 return (-1); 335 break; 336 default: 337 fatalx("if_join_group: unknown interface type"); 338 } 339 340 return (0); 341 } 342 343 int 344 if_leave_group(struct iface *iface, struct in_addr *addr) 345 { 346 struct ip_mreq mreq; 347 348 switch (iface->type) { 349 case IF_TYPE_POINTOPOINT: 350 case IF_TYPE_BROADCAST: 351 mreq.imr_multiaddr.s_addr = addr->s_addr; 352 mreq.imr_interface.s_addr = iface->addr.s_addr; 353 354 if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 355 (void *)&mreq, sizeof(mreq)) < 0) 356 return (-1); 357 break; 358 default: 359 fatalx("if_leave_group: unknown interface type"); 360 } 361 362 return (0); 363 } 364 365 struct iface * 366 if_new(struct kif *kif) 367 { 368 struct sockaddr_in *sain; 369 struct iface *iface; 370 struct ifreq *ifr; 371 int s; 372 373 if ((iface = calloc(1, sizeof(*iface))) == NULL) 374 err(1, "if_new: calloc"); 375 376 iface->state = IF_STA_DOWN; 377 378 LIST_INIT(&iface->nbr_list); 379 TAILQ_INIT(&iface->rp_list); 380 TAILQ_INIT(&iface->rq_list); 381 382 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 383 384 if ((ifr = calloc(1, sizeof(*ifr))) == NULL) 385 err(1, "if_new: calloc"); 386 387 /* set up ifreq */ 388 strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name)); 389 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 390 err(1, "if_new: socket"); 391 392 /* get type */ 393 if (kif->flags & IFF_POINTOPOINT) 394 iface->type = IF_TYPE_POINTOPOINT; 395 if (kif->flags & IFF_BROADCAST && 396 kif->flags & IFF_MULTICAST) 397 iface->type = IF_TYPE_BROADCAST; 398 if (kif->flags & IFF_LOOPBACK) { 399 iface->type = IF_TYPE_POINTOPOINT; 400 /* XXX protect loopback from sending packets over lo? */ 401 } 402 403 /* get mtu, index and flags */ 404 iface->mtu = kif->mtu; 405 iface->ifindex = kif->ifindex; 406 iface->flags = kif->flags; 407 iface->linkstate = kif->link_state; 408 iface->media_type = kif->media_type; 409 410 /* get address */ 411 if (ioctl(s, SIOCGIFADDR, ifr) < 0) 412 err(1, "if_new: cannot get address"); 413 sain = (struct sockaddr_in *)&ifr->ifr_addr; 414 iface->addr = sain->sin_addr; 415 416 /* get mask */ 417 if (ioctl(s, SIOCGIFNETMASK, ifr) < 0) 418 err(1, "if_new: cannot get mask"); 419 sain = (struct sockaddr_in *)&ifr->ifr_addr; 420 iface->mask = sain->sin_addr; 421 422 /* get p2p dst address */ 423 if (kif->flags & IFF_POINTOPOINT) { 424 if (ioctl(s, SIOCGIFDSTADDR, ifr) < 0) 425 err(1, "if_new: cannot get dst addr"); 426 sain = (struct sockaddr_in *)&ifr->ifr_addr; 427 iface->dst = sain->sin_addr; 428 } 429 430 free(ifr); 431 close(s); 432 433 return (iface); 434 } 435 436 void 437 if_del(struct iface *iface) 438 { 439 struct nbr *nbr; 440 441 log_debug("if_del: interface %s", iface->name); 442 443 /* clear lists etc */ 444 while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) 445 nbr_act_del(nbr); 446 447 /* XXX rq_list, rp_list */ 448 449 free(iface); 450 } 451 452 struct ctl_iface * 453 if_to_ctl(struct iface *iface) 454 { 455 static struct ctl_iface ictl; 456 struct timeval now; 457 458 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 459 memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); 460 memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); 461 462 ictl.ifindex = iface->ifindex; 463 ictl.state = iface->state; 464 ictl.mtu = iface->mtu; 465 466 ictl.baudrate = iface->baudrate; 467 ictl.flags = iface->flags; 468 ictl.metric = iface->cost; 469 ictl.type = iface->type; 470 ictl.linkstate = iface->linkstate; 471 ictl.passive = iface->passive; 472 ictl.mediatype = iface->media_type; 473 474 gettimeofday(&now, NULL); 475 476 if (iface->state != IF_STA_DOWN) { 477 ictl.uptime = now.tv_sec - iface->uptime; 478 } else 479 ictl.uptime = 0; 480 481 return (&ictl); 482 } 483