Annotation of embedaddon/coova-chilli/src/net.c, revision 1.1.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>