IBR-DTNSuite  0.10
lowpansocket.cpp
Go to the documentation of this file.
1 /*
2  * lowpansocket.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Stefan Schmidt <stefan@datenfreihafen.org>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "ibrcommon/config.h"
24 #include "ibrcommon/Logger.h"
25 #include <sys/socket.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <sstream>
33 #include <iomanip>
34 
35 #if defined HAVE_LIBNL || HAVE_LIBNL3
36 #include <netlink/route/link.h>
37 #include <netlink/route/addr.h>
38 #include <netlink/genl/genl.h>
39 #include <netlink/genl/ctrl.h>
40 #endif
41 
42 extern "C" {
45 extern struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1];
46 }
47 
48 namespace ibrcommon
49 {
50  lowpansocket::lowpansocket(const uint16_t &panid, const vinterface &iface)
51  : _panid(panid), _iface(iface)
52  {
53  }
54 
56  {
57 
58  }
59 
61  {
62  if (_state != SOCKET_DOWN)
63  throw socket_exception("socket is already up");
64 
65  // Create socket for listening for client connection requests.
66  init_socket(PF_IEEE802154, SOCK_DGRAM, 0);
67 
68  struct sockaddr_ieee802154 sockaddr;
69  bzero(&sockaddr, sizeof(sockaddr));
70 
71  sockaddr.family = AF_IEEE802154;
73  sockaddr.addr.pan_id = _panid;
74 
75  // Get address via netlink
76  getAddress(&sockaddr.addr, _iface);
77 
78  if ( ::bind(_fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) < 0 )
79  {
80  throw socket_exception("cannot bind socket");
81  }
82 
83  _state = SOCKET_UP;
84  }
85 
87  {
88  if ((_state == SOCKET_DOWN) || (_state == SOCKET_DESTROYED))
89  throw socket_exception("socket is not up");
90 
91  this->close();
92  }
93 
94  void lowpansocket::setAutoAck(bool enable) throw (socket_exception)
95  {
96  int optval = (enable ? 1 : 0);
97  if (::setsockopt(_fd, SOL_IEEE802154, WPAN_WANTACK, &optval, sizeof(optval)) < 0) {
98  throw ibrcommon::socket_exception("can not set auto-ack feature");
99  }
100  }
101 
102  ssize_t lowpansocket::recvfrom(char *buf, size_t buflen, int flags, ibrcommon::vaddress &addr) throw (socket_exception)
103  {
104  struct sockaddr_storage clientAddress;
105  socklen_t clientAddressLength = sizeof(clientAddress);
106  ::memset(&clientAddress, 0, clientAddressLength);
107 
108  // data waiting
109  ssize_t ret = ::recvfrom(_fd, buf, buflen, flags, (struct sockaddr *) &clientAddress, &clientAddressLength);
110 
111  if (ret == -1) {
112  throw socket_exception("recvfrom error");
113  }
114 
115  struct sockaddr_ieee802154 *addr154 = (struct sockaddr_ieee802154*)&clientAddress;
116 
117  std::stringstream ss_pan; ss_pan << addr154->addr.pan_id;
118  std::stringstream ss_short; ss_short << addr154->addr.short_addr;
119 
120  addr = ibrcommon::vaddress(ss_short.str(), ss_pan.str(), clientAddress.ss_family);
121 
122  return ret;
123  }
124 
125  void lowpansocket::sendto(const char *buf, size_t buflen, int flags, const ibrcommon::vaddress &addr) throw (socket_exception)
126  {
127  ssize_t ret = 0;
128  struct sockaddr_ieee802154 sockaddr;
129  bzero(&sockaddr, sizeof(sockaddr));
130 
131  sockaddr.family = AF_IEEE802154;
133 
134  std::stringstream ss_pan(addr.service());
135  ss_pan >> sockaddr.addr.pan_id;
136 
137  std::stringstream ss_short(addr.address());
138  ss_short >> sockaddr.addr.short_addr;
139 
140  ::connect(_fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr));
141  //printf("lowpan send() address %04x, PAN %04x\n", _destaddress.addr.short_addr, _destaddress.addr.pan_id);
142  //return ::sendto(_socket._socket, data, length, 0, (struct sockaddr *) &_destaddress, sizeof(_destaddress));
143  ret = ::send(_fd, buf, buflen, flags);
144 
145  if (ret == -1) {
146  throw socket_raw_error(errno);
147  }
148  }
149 
150  void lowpansocket::getAddress(const vinterface &iface, const std::string &panid, ibrcommon::vaddress &addr)
151  {
152  struct sockaddr_ieee802154 address;
154 
155  lowpansocket::getAddress(&address.addr, iface);
156 
157  std::stringstream ss_pan; ss_pan << address.addr.pan_id;
158  std::stringstream ss_addr; ss_addr << address.addr.short_addr;
159 
160  addr = ibrcommon::vaddress(ss_addr.str(), panid, address.family);
161  }
162 
163  void lowpansocket::getAddress(struct ieee802154_addr *ret, const vinterface &iface)
164  {
165 #if defined HAVE_LIBNL || HAVE_LIBNL3
166 #ifdef HAVE_LIBNL3
167  struct nl_sock *nl = nl_socket_alloc();
168 #else
169  struct nl_handle *nl = nl_handle_alloc();
170 #endif
171  unsigned char *buf = NULL;
172  struct sockaddr_nl nla;
173  struct nlattr *attrs[IEEE802154_ATTR_MAX+1];
174  //struct genlmsghdr *ghdr;
175  struct nlmsghdr *nlh;
176  struct nl_msg *msg;
177  int family;
178 
179  if (!nl)
180  return;
181 
182  genl_connect(nl);
183 
184  /* Build and send message */
185  msg = nlmsg_alloc();
186  family = genl_ctrl_resolve(nl, "802.15.4 MAC");
187  genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO, IEEE802154_LIST_IFACE, 1);
188  nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, iface.toString().c_str());
189  nl_send_auto_complete(nl, msg);
190  nlmsg_free(msg);
191 
192  /* Receive and parse answer */
193  nl_recv(nl, &nla, &buf, NULL);
194  nlh = (struct nlmsghdr*)buf;
195  genlmsg_parse(nlh, 0, attrs, IEEE802154_ATTR_MAX, ieee802154_policy);
196  //ghdr = (genlmsghdr*)nlmsg_data(nlh);
198  return;
199 
200  // We only handle short addresses right now
202  ret->pan_id = nla_get_u16(attrs[IEEE802154_ATTR_PAN_ID]);
203  ret->short_addr = nla_get_u16(attrs[IEEE802154_ATTR_SHORT_ADDR]);
204 
205  free(buf);
206  nl_close(nl);
207 
208 #ifdef HAVE_LIBNL3
209  nl_socket_free(nl);
210 #else
211  nl_handle_destroy(nl);
212 #endif
213 #endif
214  }
215 }