Annotation of embedaddon/coova-chilli/src/net.c, revision 1.1
1.1 ! misho 1: /*
! 2: * net library functions.
! 3: * Copyright (C) 2003, 2004, 2005, 2006 Mondru AB.
! 4: * Copyright (c) 2006-2008 David Bird <david@coova.com>
! 5: *
! 6: * The contents of this file may be used under the terms of the GNU
! 7: * General Public License Version 2, provided that the above copyright
! 8: * notice and this permission notice is included in all copies or
! 9: * substantial portions of the software.
! 10: *
! 11: */
! 12:
! 13: #include "system.h"
! 14: #include "syserr.h"
! 15: #include "options.h"
! 16: #include "net.h"
! 17:
! 18: int dev_set_flags(char const *dev, int flags) {
! 19: struct ifreq ifr;
! 20: int fd;
! 21:
! 22: memset(&ifr, 0, sizeof(ifr));
! 23: ifr.ifr_flags = flags;
! 24: strncpy(ifr.ifr_name, dev, IFNAMSIZ);
! 25: ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
! 26:
! 27: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 28: log_err(errno,"socket() failed");
! 29: return -1;
! 30: }
! 31:
! 32: if (ioctl(fd, SIOCSIFFLAGS, &ifr)) {
! 33: log_err(errno,"ioctl(SIOCSIFFLAGS) failed");
! 34: close(fd);
! 35: return -1;
! 36: }
! 37:
! 38: close(fd);
! 39:
! 40: return 0;
! 41: }
! 42:
! 43: int dev_get_flags(char const *dev, int *flags) {
! 44: struct ifreq ifr;
! 45: int fd;
! 46:
! 47: memset(&ifr, 0, sizeof(ifr));
! 48: strncpy(ifr.ifr_name, dev, IFNAMSIZ);
! 49: ifr.ifr_name[IFNAMSIZ-1] = 0;
! 50:
! 51: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 52: log_err(errno, "socket() failed");
! 53: return -1;
! 54: }
! 55:
! 56: if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
! 57: log_err(errno, "ioctl(SIOCSIFFLAGS) failed");
! 58: close(fd);
! 59: return -1;
! 60: }
! 61:
! 62: close(fd);
! 63:
! 64: *flags = ifr.ifr_flags;
! 65:
! 66: return 0;
! 67: }
! 68:
! 69: int dev_set_address(char const *devname, struct in_addr *address,
! 70: struct in_addr *dstaddr, struct in_addr *netmask) {
! 71: struct ifreq ifr;
! 72: int fd;
! 73:
! 74: memset (&ifr, 0, sizeof (ifr));
! 75: ifr.ifr_addr.sa_family = AF_INET;
! 76: ifr.ifr_dstaddr.sa_family = AF_INET;
! 77:
! 78: #if defined(__linux__)
! 79: ifr.ifr_netmask.sa_family = AF_INET;
! 80:
! 81: #elif defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 82: ((struct sockaddr_in *) &ifr.ifr_addr)->sin_len = sizeof (struct sockaddr_in);
! 83: ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_len = sizeof (struct sockaddr_in);
! 84: #endif
! 85:
! 86: strncpy(ifr.ifr_name, devname, IFNAMSIZ);
! 87: ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
! 88:
! 89: /* Create a channel to the NET kernel. */
! 90: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 91: log_err(errno, "socket() failed");
! 92: return -1;
! 93: }
! 94:
! 95: if (address) { /* Set the interface address */
! 96: ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = address->s_addr;
! 97: if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) {
! 98: if (errno != EEXIST) {
! 99: log_err(errno, "ioctl(SIOCSIFADDR) failed");
! 100: }
! 101: else {
! 102: log_warn(errno, "ioctl(SIOCSIFADDR): Address already exists");
! 103: }
! 104: close(fd);
! 105: return -1;
! 106: }
! 107: }
! 108:
! 109: if (dstaddr) { /* Set the destination address */
! 110: ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = dstaddr->s_addr;
! 111: if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
! 112: log_err(errno, "ioctl(SIOCSIFDSTADDR) failed");
! 113: close(fd);
! 114: return -1;
! 115: }
! 116: }
! 117:
! 118: if (netmask) { /* Set the netmask */
! 119: #if defined(__linux__)
! 120: ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr = netmask->s_addr;
! 121:
! 122: #elif defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 123: ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = netmask->s_addr;
! 124:
! 125: #elif defined(__sun__)
! 126: ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = netmask->s_addr;
! 127: #else
! 128: #error "Unknown platform!"
! 129: #endif
! 130:
! 131: if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
! 132: log_err(errno, "ioctl(SIOCSIFNETMASK) failed");
! 133: close(fd);
! 134: return -1;
! 135: }
! 136: }
! 137:
! 138: close(fd);
! 139:
! 140: return dev_set_flags(devname, IFF_UP | IFF_RUNNING);
! 141: }
! 142:
! 143: int net_init(net_interface *netif, char *ifname, uint16_t protocol, int promisc, uint8_t *mac) {
! 144: memset(netif, 0, sizeof(net_interface));
! 145: strncpy(netif->devname, ifname, IFNAMSIZ);
! 146: netif->devname[IFNAMSIZ] = 0;
! 147: netif->protocol = protocol;
! 148:
! 149: if (promisc) netif->flags |= NET_PROMISC;
! 150:
! 151: if (mac) {
! 152: netif->flags |= NET_USEMAC;
! 153: memcpy(netif->hwaddr, mac, PKT_ETH_ALEN);
! 154: }
! 155:
! 156: return net_open(netif);
! 157: }
! 158:
! 159: int net_open(net_interface *netif) {
! 160: net_close(netif);
! 161: net_gflags(netif);
! 162:
! 163: if (!(netif->devflags & IFF_UP) || !(netif->devflags & IFF_RUNNING)) {
! 164: struct in_addr noaddr;
! 165: net_sflags(netif, netif->devflags | IFF_NOARP);
! 166: memset(&noaddr, 0, sizeof(noaddr));
! 167: dev_set_address(netif->devname, &noaddr, NULL, NULL);
! 168: }
! 169:
! 170: return net_open_eth(netif);
! 171: }
! 172:
! 173: int net_reopen(net_interface *netif) {
! 174: net_close(netif);
! 175: return net_open(netif);
! 176: }
! 177:
! 178: int net_set_address(net_interface *netif, struct in_addr *address,
! 179: struct in_addr *dstaddr, struct in_addr *netmask) {
! 180: netif->address.s_addr = address->s_addr;
! 181: netif->gateway.s_addr = dstaddr->s_addr;
! 182: netif->netmask.s_addr = netmask->s_addr;
! 183:
! 184: return dev_set_address(netif->devname, address, dstaddr, netmask);
! 185: }
! 186:
! 187: ssize_t net_read(net_interface *netif, void *d, size_t dlen) {
! 188: ssize_t len;
! 189:
! 190: if ((len = read(netif->fd, d, dlen)) < 0) {
! 191: #ifdef ENETDOWN
! 192: if (errno == ENETDOWN) {
! 193: net_reopen(netif);
! 194: }
! 195: #endif
! 196: log_err(errno, "read(fd=%d, len=%d) == %d", netif->fd, dlen, len);
! 197: return -1;
! 198: }
! 199:
! 200: return len;
! 201: }
! 202:
! 203: ssize_t net_write(net_interface *netif, void *d, size_t dlen) {
! 204: ssize_t len;
! 205:
! 206: if ((len = write(netif->fd, d, dlen)) < 0) {
! 207: #ifdef ENETDOWN
! 208: if (errno == ENETDOWN) {
! 209: net_reopen(netif);
! 210: }
! 211: #endif
! 212: log_err(errno, "write(fd=%d, len=%d) failed", netif->fd, dlen);
! 213: return -1;
! 214: }
! 215:
! 216: return len;
! 217: }
! 218:
! 219: int net_route(struct in_addr *dst, struct in_addr *gateway, struct in_addr *mask, int delete) {
! 220:
! 221: /* TODO: solaris! */
! 222:
! 223: #if defined(__linux__)
! 224: struct rtentry r;
! 225: int fd;
! 226:
! 227: memset (&r, 0, sizeof (r));
! 228: r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */
! 229:
! 230: /* Create a channel to the NET kernel. */
! 231: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 232: log_err(errno, "socket() failed");
! 233: return -1;
! 234: }
! 235:
! 236: r.rt_dst.sa_family = AF_INET;
! 237: r.rt_gateway.sa_family = AF_INET;
! 238: r.rt_genmask.sa_family = AF_INET;
! 239: ((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
! 240: ((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
! 241: ((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
! 242:
! 243: if (delete) {
! 244: if (ioctl(fd, SIOCDELRT, (void *) &r) < 0) {
! 245: log_err(errno,"ioctl(SIOCDELRT) failed");
! 246: close(fd);
! 247: return -1;
! 248: }
! 249: }
! 250: else {
! 251: if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) {
! 252: log_err(errno, "ioctl(SIOCADDRT) failed");
! 253: close(fd);
! 254: return -1;
! 255: }
! 256: }
! 257: close(fd);
! 258: return 0;
! 259:
! 260: #elif defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 261:
! 262: struct {
! 263: struct rt_msghdr rt;
! 264: struct sockaddr_in dst;
! 265: struct sockaddr_in gate;
! 266: struct sockaddr_in mask;
! 267: } req;
! 268:
! 269: int fd;
! 270: struct rt_msghdr *rtm;
! 271:
! 272: if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
! 273: log_err(errno, "socket() failed");
! 274: return -1;
! 275: }
! 276:
! 277: memset(&req, 0, sizeof(req));
! 278:
! 279: rtm = &req.rt;
! 280:
! 281: rtm->rtm_msglen = sizeof(req);
! 282: rtm->rtm_version = RTM_VERSION;
! 283: if (delete) {
! 284: rtm->rtm_type = RTM_DELETE;
! 285: }
! 286: else {
! 287: rtm->rtm_type = RTM_ADD;
! 288: }
! 289: rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; /* TODO */
! 290: rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
! 291: rtm->rtm_pid = getpid();
! 292: rtm->rtm_seq = 0044; /* TODO */
! 293:
! 294: req.dst.sin_family = AF_INET;
! 295: req.dst.sin_len = sizeof(req.dst);
! 296: req.mask.sin_family = AF_INET;
! 297: req.mask.sin_len = sizeof(req.mask);
! 298: req.gate.sin_family = AF_INET;
! 299: req.gate.sin_len = sizeof(req.gate);
! 300:
! 301: req.dst.sin_addr.s_addr = dst->s_addr;
! 302: req.mask.sin_addr.s_addr = mask->s_addr;
! 303: req.gate.sin_addr.s_addr = gateway->s_addr;
! 304:
! 305: if (write(fd, rtm, rtm->rtm_msglen) < 0) {
! 306: log_err(errno, "write() failed");
! 307: close(fd);
! 308: return -1;
! 309: }
! 310: close(fd);
! 311: return 0;
! 312:
! 313: #elif defined(__sun__)
! 314: log_err(errno, "Could not set up routing on Solaris. Please add route manually.");
! 315: return 0;
! 316: #else
! 317: #error "Unknown platform!"
! 318: #endif
! 319: }
! 320:
! 321: #if defined(__linux__)
! 322:
! 323: /**
! 324: * Opens an Ethernet interface. As an option the interface can be set in
! 325: * promisc mode. If not null macaddr and ifindex are filled with the
! 326: * interface mac address and index
! 327: **/
! 328: int net_open_eth(net_interface *netif) {
! 329: struct ifreq ifr;
! 330: struct packet_mreq mr;
! 331: struct sockaddr_ll sa;
! 332: int option = 1;
! 333:
! 334: memset(&ifr, 0, sizeof(ifr));
! 335:
! 336: /* Create socket */
! 337: if ((netif->fd = socket(PF_PACKET, SOCK_RAW, htons(netif->protocol))) < 0) {
! 338: if (errno == EPERM) {
! 339: log_err(errno, "Cannot create raw socket. Must be root.");
! 340: }
! 341:
! 342: log_err(errno, "socket(domain=%d, type=%lx, protocol=%d) failed",
! 343: PF_PACKET, SOCK_RAW, netif->protocol);
! 344:
! 345: return -1;
! 346: }
! 347:
! 348: /* Enable reception and transmission of broadcast frames */
! 349: if (setsockopt(netif->fd, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)) < 0) {
! 350: log_err(errno, "setsockopt(s=%d, level=%d, optname=%d, optlen=%d) failed",
! 351: netif->fd, SOL_SOCKET, SO_BROADCAST, sizeof(option));
! 352: return -1;
! 353: }
! 354:
! 355: /* Get the MAC address of our interface */
! 356: strncpy(ifr.ifr_name, netif->devname, sizeof(ifr.ifr_name));
! 357: if (ioctl(netif->fd, SIOCGIFHWADDR, &ifr) < 0) {
! 358: log_err(errno, "ioctl(d=%d, request=%d) failed", netif->fd, SIOCGIFHWADDR);
! 359: return -1;
! 360: }
! 361:
! 362: if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
! 363:
! 364: netif->flags |= NET_ETHHDR;
! 365:
! 366: if ((netif->flags & NET_USEMAC) == 0)
! 367: memcpy(netif->hwaddr, ifr.ifr_hwaddr.sa_data, PKT_ETH_ALEN);
! 368: }
! 369:
! 370: if (netif->hwaddr[0] & 0x01) {
! 371: log_err(0, "Ethernet has broadcast or multicast address: %.16s", netif->devname);
! 372: }
! 373:
! 374: /* Get the current interface address, network, and any destination address */
! 375:
! 376: /* Verify that MTU = ETH_DATA_LEN */
! 377: strncpy(ifr.ifr_name, netif->devname, sizeof(ifr.ifr_name));
! 378: if (ioctl(netif->fd, SIOCGIFMTU, &ifr) < 0) {
! 379: log_err(errno, "ioctl(d=%d, request=%d) failed", netif->fd, SIOCGIFMTU);
! 380: return -1;
! 381: }
! 382: if (ifr.ifr_mtu != ETH_DATA_LEN) {
! 383: log_err(0, "MTU does not match EHT_DATA_LEN: %d %d", ifr.ifr_mtu, ETH_DATA_LEN);
! 384: return -1;
! 385: }
! 386:
! 387: /* Get ifindex */
! 388: strncpy(ifr.ifr_name, netif->devname, sizeof(ifr.ifr_name));
! 389: if (ioctl(netif->fd, SIOCGIFINDEX, &ifr) < 0) {
! 390: log_err(errno, "ioctl(SIOCFIGINDEX) failed");
! 391: }
! 392: netif->ifindex = ifr.ifr_ifindex;
! 393:
! 394: /* Set interface in promisc mode */
! 395: if (netif->flags & NET_PROMISC) {
! 396: memset(&mr,0,sizeof(mr));
! 397: mr.mr_ifindex = ifr.ifr_ifindex;
! 398: mr.mr_type = PACKET_MR_PROMISC;
! 399: if (setsockopt(netif->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (char *)&mr, sizeof(mr)) < 0) {
! 400: log_err(errno, "setsockopt(s=%d, level=%d, optname=%d, optlen=%d) failed",
! 401: netif->fd, SOL_SOCKET, PACKET_ADD_MEMBERSHIP, sizeof(mr));
! 402: return -1;
! 403: }
! 404: }
! 405:
! 406: /* Bind to particular interface */
! 407: memset(&sa, 0, sizeof(sa));
! 408: sa.sll_family = AF_PACKET;
! 409: sa.sll_protocol = htons(netif->protocol);
! 410: sa.sll_ifindex = ifr.ifr_ifindex;
! 411:
! 412: if (bind(netif->fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
! 413: log_err(errno, "bind(sockfd=%d) failed", netif->fd);
! 414: return -1;
! 415: }
! 416:
! 417: return 0;
! 418: }
! 419:
! 420: #elif defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 421:
! 422: int net_getmac(const char *ifname, char *macaddr) {
! 423:
! 424: struct ifaddrs *ifap, *ifa;
! 425: struct sockaddr_dl *sdl;
! 426:
! 427: if (getifaddrs(&ifap)) {
! 428: log_err(errno, "getifaddrs() failed!");
! 429: return -1;
! 430: }
! 431:
! 432: ifa = ifap;
! 433: while (ifa) {
! 434: if ((strcmp(ifa->ifa_name, ifname) == 0) &&
! 435: (ifa->ifa_addr->sa_family == AF_LINK)) {
! 436: sdl = (struct sockaddr_dl *)ifa->ifa_addr;
! 437: switch(sdl->sdl_type) {
! 438: case IFT_ETHER:
! 439: #ifdef IFT_IEEE80211
! 440: case IFT_IEEE80211:
! 441: #endif
! 442: break;
! 443: default:
! 444: continue;
! 445: }
! 446: if (sdl->sdl_alen != PKT_ETH_ALEN) {
! 447: log_err(errno, "Wrong sdl_alen!");
! 448: freeifaddrs(ifap);
! 449: return -1;
! 450: }
! 451: memcpy(macaddr, LLADDR(sdl), PKT_ETH_ALEN);
! 452: freeifaddrs(ifap);
! 453: return 0;
! 454: }
! 455: ifa = ifa->ifa_next;
! 456: }
! 457: freeifaddrs(ifap);
! 458: return -1;
! 459: }
! 460:
! 461: /**
! 462: * Opens an Ethernet interface. As an option the interface can be set in
! 463: * promisc mode. If not null macaddr and ifindex are filled with the
! 464: * interface mac address and index
! 465: **/
! 466:
! 467: /* Relevant IOCTLs
! 468: FIONREAD Get the number of bytes in input buffer
! 469: SIOCGIFADDR Get interface address (IP)
! 470: BIOCGBLEN, BIOCSBLEN Get and set required buffer length
! 471: BIOCGDLT Type of underlying data interface
! 472: BIOCPROMISC Set in promisc mode
! 473: BIOCFLUSH Flushes the buffer of incoming packets
! 474: BIOCGETIF, BIOCSETIF Set hardware interface. Uses ift_name
! 475: BIOCSRTIMEOUT, BIOCGRTIMEOUT Set and get timeout for reads
! 476: BIOCGSTATS Return stats for the interface
! 477: BIOCIMMEDIATE Return immediately from reads as soon as packet arrives.
! 478: BIOCSETF Set filter
! 479: BIOCVERSION Return the version of BPF
! 480: BIOCSHDRCMPLT BIOCGHDRCMPLT Set flag of wheather to fill in MAC address
! 481: BIOCSSEESENT BIOCGSEESENT Return locally generated packets */
! 482:
! 483: int net_open_eth(net_interface *netif) {
! 484: char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
! 485: int devnum;
! 486: struct ifreq ifr;
! 487: struct ifaliasreq areq;
! 488: int local_fd;
! 489: struct bpf_version bv;
! 490:
! 491: u_int32_t ipaddr;
! 492: struct sockaddr_dl hwaddr;
! 493: unsigned int value;
! 494:
! 495: /* Find suitable device */
! 496: for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
! 497: snprintf(devname, sizeof(devname), "/dev/bpf%d", devnum);
! 498: devname[sizeof(devname)] = 0;
! 499: if ((netif->fd = open(devname, O_RDWR)) >= 0) break;
! 500: if (errno != EBUSY) break;
! 501: }
! 502: if (netif->fd < 0) {
! 503: log_err(errno, "Can't find bpf device");
! 504: return -1;
! 505: }
! 506:
! 507: /* Set the interface */
! 508: memset(&ifr, 0, sizeof(ifr));
! 509: strncpy(ifr.ifr_name, netif->devname, sizeof(ifr.ifr_name));
! 510: if (ioctl(netif->fd, BIOCSETIF, &ifr) < 0) {
! 511: log_err(errno,"ioctl() failed");
! 512: return -1;
! 513: }
! 514:
! 515: /* Get and validate BPF version */
! 516: if (ioctl(netif->fd, BIOCVERSION, &bv) < 0) {
! 517: log_err(errno,"ioctl() failed!");
! 518: return -1;
! 519: }
! 520: if (bv.bv_major != BPF_MAJOR_VERSION ||
! 521: bv.bv_minor < BPF_MINOR_VERSION) {
! 522: log_err(errno,"wrong BPF version!");
! 523: return -1;
! 524: }
! 525:
! 526: /* Get the MAC address of our interface */
! 527: if (net_getmac(netif->devname, netif->hwaddr)) {
! 528: log_err(0,"Did not find MAC address!");
! 529: }
! 530: else {
! 531: netif->flags |= NET_ETHHDR;
! 532: }
! 533:
! 534: if (netif->hwaddr[0] & 0x01) {
! 535: log_err(0, "Ethernet has broadcast or multicast address: %.16s", netif->devname);
! 536: return -1;
! 537: }
! 538:
! 539: /* Set interface in promisc mode */
! 540: if (netif->flags & NET_PROMISC) {
! 541: value = 1;
! 542: if (ioctl(netif->fd, BIOCPROMISC, NULL) < 0) {
! 543: log_err(errno,"ioctl() failed!");
! 544: return -1;
! 545: }
! 546: value = 1;
! 547: if (ioctl(netif->fd, BIOCSHDRCMPLT, &value) < 0) {
! 548: log_err(errno,"ioctl() failed!");
! 549: return -1;
! 550: }
! 551: }
! 552: else {
! 553: value = 0;
! 554: if (ioctl(netif->fd, BIOCSHDRCMPLT, &value) < 0) {
! 555: log_err(errno,"ioctl() failed!");
! 556: return -1;
! 557: }
! 558: }
! 559:
! 560: /* Make sure reads return as soon as packet has been received */
! 561: value = 1;
! 562: if (ioctl(netif->fd, BIOCIMMEDIATE, &value) < 0) {
! 563: log_err(errno,"ioctl() failed!");
! 564: return -1;
! 565: }
! 566:
! 567: return 0;
! 568: }
! 569:
! 570: #endif
! 571:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>