File: netlink.c

package info (click to toggle)
gpe-mininet 0.7-2
  • links: PTS
  • area: main
  • in suites: lenny, squeeze, wheezy
  • size: 860 kB
  • ctags: 162
  • sloc: sh: 8,474; ansic: 956; xml: 68; makefile: 40
file content (165 lines) | stat: -rw-r--r-- 3,543 bytes parent folder | download
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);
	}
    }
}