1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
/*
* Netlink code for gpe-mininet
*
* Copyright (C) 2004 Philip Blundell <philb@gnu.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include "iwlib.h"
#include "netlink.h"
#include "main.h"
int
rtnl_open (void)
{
int fd;
struct sockaddr_nl local;
fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0)
{
perror ("socket AF_NETLINK");
return -1;
}
memset (&local, 0, sizeof (local));
local.nl_family = AF_NETLINK;
local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
if (bind (fd, (struct sockaddr*)&local, sizeof (local)) < 0)
{
perror("Cannot bind netlink socket");
close (fd);
return -1;
}
if (fcntl (fd, F_SETFL, O_NONBLOCK))
{
perror ("fcntl O_NONBLOCK");
close (fd);
return -1;
}
return fd;
}
static void
rtnl_wireless_event (struct iw_event *iwe)
{
if (iwe->cmd == SIOCSIWESSID)
{
update_wireless(iwe->u.essid.pointer);
printf("essid %s %i\n",iwe->u.essid.pointer,iwe->len);
}
if (iwe->cmd == SIOCGIWAP)
printf("ap %2x:%2x:%2x:%2x:%2x:%2x: %i\n",iwe->u.ap_addr.sa_data[0],iwe->u.ap_addr.sa_data[1],
iwe->u.ap_addr.sa_data[2],iwe->u.ap_addr.sa_data[3],iwe->u.ap_addr.sa_data[4],iwe->u.ap_addr.sa_data[5],
iwe->len);
// do something appropriate
}
static void
rtnl_routing_event (struct rtmsg *rtm)
{
if (rtm->rtm_dst_len == 0)
{
// the default route has changed
update_netstatus ();
}
}
static void
rtnl_dispatch (struct sockaddr_nl *nladdr, struct nlmsghdr *h)
{
struct ifinfomsg *ifi;
struct stream_descr stream;
struct iw_event iwe;
int ret;
switch (h->nlmsg_type)
{
case RTM_NEWLINK:
ifi = NLMSG_DATA (h);
/* Code is ugly, but sort of works - Jean II */
/* Check for attributes */
if (h->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg))) {
int attrlen = h->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
struct rtattr *attr = (void*)ifi + NLMSG_ALIGN(sizeof(struct ifinfomsg));
while (RTA_OK(attr, attrlen)) {
/* Check if the Wireless kind */
if(attr->rta_type == IFLA_WIRELESS) {
iw_init_event_stream(&stream,
(void *)attr + RTA_ALIGN(sizeof(struct rtattr)),
attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
do
{
ret = iw_extract_event_stream (&stream, &iwe);
if (ret > 0)
rtnl_wireless_event (&iwe);
}
while(ret > 0);
}
attr = RTA_NEXT(attr, attrlen);
}
}
break;
case RTM_NEWROUTE:
case RTM_DELROUTE:
rtnl_routing_event (NLMSG_DATA (h));
break;
}
}
void
rtnl_process (int fd)
{
char buf[8192];
struct sockaddr_nl nladdr;
struct iovec iov = { buf, sizeof(buf) };
int status;
struct nlmsghdr *h;
struct msghdr msg = {
(void*)&nladdr, sizeof(nladdr),
&iov, 1,
NULL, 0,
0
};
for (;;)
{
status = recvmsg (fd, &msg, 0);
if (status <= 0)
break;
if (msg.msg_namelen != sizeof (nladdr))
continue;
h = (struct nlmsghdr*)buf;
while (NLMSG_OK (h, status))
{
rtnl_dispatch (&nladdr, h);
h = NLMSG_NEXT (h, status);
}
}
}
|