00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef QOLYESTER_SYS_LINUX_NETLINK_HXX
00021 # define QOLYESTER_SYS_LINUX_NETLINK_HXX 1
00022
00023 # include <cstring>
00024 # include <asm/types.h>
00025 # include <sys/socket.h>
00026 # include <linux/rtnetlink.h>
00027 # include <linux/pkt_sched.h>
00028 # include <stdexcept>
00029 # include <cerrno>
00030
00031 # include "netlink.hh"
00032
00033 namespace olsr {
00034
00035 namespace sys {
00036
00037 namespace netlink {
00038
00039 RequestVisitor::RequestVisitor()
00040 : _buffers(),
00041 _buffer(0),
00042 _length(0)
00043 {}
00044
00045 RequestVisitor::~RequestVisitor() {
00046 for (buffers_t::iterator i = _buffers.begin();
00047 i != _buffers.end();
00048 ++i)
00049 delete[] (char*) i->iov_base;
00050 if (_buffer != 0)
00051 delete[] _buffer;
00052 }
00053
00054 # define PREPARE_MESSAGE(Payload, Name) \
00055 nlmsghdr* nh; \
00056 Payload * Name ; \
00057 int len = NLMSG_SPACE(sizeof ( Payload )); \
00058 char* r = new char[len]; \
00059 memset(r, 0, len); \
00060 \
00061 nh = reinterpret_cast<nlmsghdr*>(r); \
00062 Name = reinterpret_cast< Payload *>(NLMSG_DATA(nh)); \
00063 \
00064 nh->nlmsg_len = NLMSG_LENGTH(sizeof ( Payload )); \
00065 nh->nlmsg_seq = RequestVisitor::seqnum++; \
00066 nh->nlmsg_pid = 0;
00067
00068 # define PREPARE_MESSAGE_GET(Payload, Name) \
00069 PREPARE_MESSAGE(Payload, Name); \
00070 nh->nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST
00071
00072 # define PREPARE_MESSAGE_NEW(Payload, Name) \
00073 PREPARE_MESSAGE(Payload, Name); \
00074 nh->nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | \
00075 NLM_F_REQUEST | NLM_F_ACK
00076
00077 # define PREPARE_MESSAGE_DEL(Payload, Name) \
00078 PREPARE_MESSAGE(Payload, Name); \
00079 nh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK
00080
00081 # define SHIPOUT_MESSAGE \
00082 iovec i = { r, len }; \
00083 _buffers.push_back(i)
00084
00085 void
00086 RequestVisitor::visit(const NLGetLink&) {
00087 PREPARE_MESSAGE_GET(ifinfomsg, ii);
00088
00089 nh->nlmsg_type = RTM_GETLINK;
00090
00091 ii->ifi_family = AF_UNSPEC;
00092
00093 SHIPOUT_MESSAGE;
00094 }
00095
00096 void
00097 RequestVisitor::visit(const NLNewAddr& e) {
00098 PREPARE_MESSAGE_NEW(ifaddrmsg, ia);
00099
00100 nh->nlmsg_type = RTM_NEWADDR;
00101
00102 ia->ifa_family = e.family();
00103 ia->ifa_prefixlen = e.prefixlen();
00104 ia->ifa_flags = e.flags();
00105 ia->ifa_scope = e.scope();
00106 ia->ifa_index = e.index();
00107
00108 SHIPOUT_MESSAGE;
00109
00110 for (NLNewAddr::attrs_t::const_iterator i = e.attrs().begin();
00111 i != e.attrs().end(); ++i)
00112 (*i)->accept(*this);
00113 }
00114
00115 void
00116 RequestVisitor::visit(const NLGetAddr& e) {
00117 PREPARE_MESSAGE_GET(ifaddrmsg, ia);
00118
00119 nh->nlmsg_type = RTM_GETADDR;
00120
00121 ia->ifa_family = e.family();
00122
00123 SHIPOUT_MESSAGE;
00124 }
00125
00126 void
00127 RequestVisitor::visit(const NLDelAddr& e) {
00128 PREPARE_MESSAGE_DEL(ifaddrmsg, ia);
00129
00130 nh->nlmsg_type = RTM_DELADDR;
00131
00132 ia->ifa_family = e.family();
00133 ia->ifa_prefixlen = e.prefixlen();
00134 ia->ifa_flags = e.flags();
00135 ia->ifa_scope = e.scope();
00136 ia->ifa_index = e.index();
00137
00138 SHIPOUT_MESSAGE;
00139
00140 for (NLDelAddr::attrs_t::const_iterator i = e.attrs().begin();
00141 i != e.attrs().end(); ++i)
00142 (*i)->accept(*this);
00143 }
00144
00145 void
00146 RequestVisitor::visit(const NLGetRoute& e) {
00147 PREPARE_MESSAGE_GET(rtmsg, rt);
00148
00149 nh->nlmsg_type = RTM_GETROUTE;
00150
00151 rt->rtm_family = e.family();
00152
00153 SHIPOUT_MESSAGE;
00154 }
00155
00156 void
00157 RequestVisitor::visit(const NLNewRoute& e) {
00158 PREPARE_MESSAGE_NEW(rtmsg, rt);
00159
00160 nh->nlmsg_type = RTM_NEWROUTE;
00161
00162 rt->rtm_family = e.family();
00163 rt->rtm_dst_len = e.dlen();
00164 rt->rtm_src_len = e.slen();
00165 rt->rtm_tos = e.tos();
00166 rt->rtm_table = e.table();
00167 rt->rtm_protocol = e.proto();
00168 rt->rtm_scope = e.scope();
00169 rt->rtm_type = e.type();
00170 rt->rtm_flags = e.flags();
00171
00172 SHIPOUT_MESSAGE;
00173
00174 for (NLNewRoute::attrs_t::const_iterator i = e.attrs().begin();
00175 i != e.attrs().end(); ++i)
00176 (*i)->accept(*this);
00177 }
00178
00179 void
00180 RequestVisitor::visit(const NLDelRoute& e) {
00181 PREPARE_MESSAGE_DEL(rtmsg, rt);
00182
00183 nh->nlmsg_type = RTM_DELROUTE;
00184
00185 rt->rtm_family = e.family();
00186 rt->rtm_dst_len = e.dlen();
00187 rt->rtm_src_len = e.slen();
00188 rt->rtm_tos = e.tos();
00189 rt->rtm_table = e.table();
00190 rt->rtm_protocol = e.proto();
00191 rt->rtm_scope = e.scope();
00192 rt->rtm_type = e.type();
00193 rt->rtm_flags = e.flags();
00194
00195 SHIPOUT_MESSAGE;
00196
00197 for (NLDelRoute::attrs_t::const_iterator i = e.attrs().begin();
00198 i != e.attrs().end(); ++i)
00199 (*i)->accept(*this);
00200 }
00201
00202 void
00203 RequestVisitor::visit(const NLAddrAttrAddress& e) {
00204 unsigned len = RTA_SPACE(e.length());
00205 char* buffer = new char[len];
00206 memset(buffer, 0, len);
00207
00208 rtattr* a = reinterpret_cast<rtattr*>(buffer);
00209 a->rta_len = RTA_LENGTH(e.length());
00210 a->rta_type = IFA_ADDRESS;
00211 memcpy(RTA_DATA(a), e.bytes(), e.length());
00212
00213 iovec i = { buffer, len };
00214
00215 _buffers.push_back(i);
00216
00217 nlmsghdr* h =
00218 reinterpret_cast<nlmsghdr*>(_buffers.begin()->iov_base);
00219
00220 h->nlmsg_len += NLMSG_ALIGN(len);
00221 }
00222
00223 void
00224 RequestVisitor::visit(const NLAddrAttrLocal& e) {
00225 unsigned len = RTA_SPACE(e.length());
00226 char* buffer = new char[len];
00227 memset(buffer, 0, len);
00228
00229 rtattr* a = reinterpret_cast<rtattr*>(buffer);
00230 a->rta_len = RTA_LENGTH(e.length());
00231 a->rta_type = IFA_LOCAL;
00232 memcpy(RTA_DATA(a), e.bytes(), e.length());
00233
00234 iovec i = { buffer, len };
00235
00236 _buffers.push_back(i);
00237
00238 nlmsghdr* h =
00239 reinterpret_cast<nlmsghdr*>(_buffers.begin()->iov_base);
00240
00241 h->nlmsg_len += NLMSG_ALIGN(len);
00242 }
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 void
00266 RequestVisitor::visit(const NLAddrAttrBroadcast& e) {
00267 unsigned len = RTA_SPACE(e.length());
00268 char* buffer = new char[len];
00269 memset(buffer, 0, len);
00270
00271 rtattr* a = reinterpret_cast<rtattr*>(buffer);
00272 a->rta_len = RTA_LENGTH(e.length());
00273 a->rta_type = IFA_BROADCAST;
00274 memcpy(RTA_DATA(a), e.bytes(), e.length());
00275
00276 iovec i = { buffer, len };
00277
00278 _buffers.push_back(i);
00279
00280 nlmsghdr* h =
00281 reinterpret_cast<nlmsghdr*>(_buffers.begin()->iov_base);
00282
00283 h->nlmsg_len += NLMSG_ALIGN(len);
00284 }
00285
00286 void
00287 RequestVisitor::visit(const NLAddrAttrAnycast& e) {
00288 unsigned len = RTA_SPACE(e.length());
00289 char* buffer = new char[len];
00290 memset(buffer, 0, len);
00291
00292 rtattr* a = reinterpret_cast<rtattr*>(buffer);
00293 a->rta_len = RTA_LENGTH(e.length());
00294 a->rta_type = IFA_ANYCAST;
00295 memcpy(RTA_DATA(a), e.bytes(), e.length());
00296
00297 iovec i = { buffer, len };
00298
00299 _buffers.push_back(i);
00300
00301 nlmsghdr* h =
00302 reinterpret_cast<nlmsghdr*>(_buffers.begin()->iov_base);
00303
00304 h->nlmsg_len += NLMSG_ALIGN(len);
00305 }
00306
00307 void
00308 RequestVisitor::visit(const NLRouteAttrDestination& e) {
00309 unsigned len = RTA_SPACE(e.length());
00310 char* buffer = new char[len];
00311 memset(buffer, 0, len);
00312
00313 rtattr* a = reinterpret_cast<rtattr*>(buffer);
00314 a->rta_len = RTA_LENGTH(e.length());
00315 a->rta_type = RTA_DST;
00316 memcpy(RTA_DATA(a), e.bytes(), e.length());
00317
00318 iovec i = { buffer, len };
00319 _buffers.push_back(i);
00320
00321 nlmsghdr* h =
00322 reinterpret_cast<nlmsghdr*>(_buffers.begin()->iov_base);
00323
00324 h->nlmsg_len += NLMSG_ALIGN(len);
00325 }
00326
00327 void
00328 RequestVisitor::visit(const NLRouteAttrGateway& e) {
00329 unsigned len = RTA_SPACE(e.length());
00330 char* buffer = new char[len];
00331 memset(buffer, 0, len);
00332
00333 rtattr* a = reinterpret_cast<rtattr*>(buffer);
00334 a->rta_len = RTA_LENGTH(e.length());
00335 a->rta_type = RTA_GATEWAY;
00336 memcpy(RTA_DATA(a), e.bytes(), e.length());
00337
00338 iovec i = { buffer, len };
00339 _buffers.push_back(i);
00340
00341 nlmsghdr* h =
00342 reinterpret_cast<nlmsghdr*>(_buffers.begin()->iov_base);
00343
00344 h->nlmsg_len += NLMSG_ALIGN(len);
00345 }
00346
00347 void
00348 RequestVisitor::visit(const NLRouteAttrOutInterface& e) {
00349 unsigned len = RTA_SPACE(sizeof (int));
00350 char* buffer = new char[len];
00351 memset(buffer, 0, len);
00352
00353 rtattr* a = reinterpret_cast<rtattr*>(buffer);
00354 a->rta_len = RTA_LENGTH(sizeof (int));
00355 a->rta_type = RTA_OIF;
00356 *(int*)RTA_DATA(a) = e.index();
00357
00358 iovec i = { buffer, len };
00359 _buffers.push_back(i);
00360
00361 nlmsghdr* h =
00362 reinterpret_cast<nlmsghdr*>(_buffers.begin()->iov_base);
00363
00364 h->nlmsg_len += NLMSG_ALIGN(len);
00365 }
00366
00367 const char*
00368 RequestVisitor::buffer() {
00369 if (_buffer != 0)
00370 return _buffer;
00371
00372 _length = totalsize();
00373 _buffer = new char[_length];
00374 memset(_buffer, 0, _length);
00375
00376 unsigned index = 0;
00377 for (buffers_t::const_iterator i = _buffers.begin();
00378 i != _buffers.end(); ++i) {
00379 memcpy(_buffer + index, i->iov_base, i->iov_len);
00380 index += NLMSG_ALIGN(i->iov_len);
00381 }
00382 return _buffer;
00383 }
00384
00385 const unsigned
00386 RequestVisitor::length() {
00387 if (_buffer == 0)
00388 buffer();
00389 return _length;
00390 }
00391
00392 unsigned
00393 RequestVisitor::totalsize() const {
00394 unsigned size = 0;
00395 for (buffers_t::const_iterator i = _buffers.begin();
00396 i != _buffers.end(); ++i)
00397 size += NLMSG_ALIGN(i->iov_len);
00398 return size;
00399 }
00400
00401 unsigned RequestVisitor::seqnum = time(NULL);
00402
00403 NLSocket::NLSocket()
00404 : _fd(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) {
00405 if (_fd < 0)
00406 throw std::runtime_error(strerror(errno));
00407 sockaddr_t snl;
00408
00409 snl.nl_family = AF_NETLINK;
00410 snl.nl_pad = 0;
00411 snl.nl_pid = 0;
00412 snl.nl_groups = 0;
00413
00414 if (bind(_fd, (sockaddr*) &snl, sizeof snl) < 0)
00415 throw std::runtime_error(strerror(errno));
00416 }
00417
00418 NLSocket::~NLSocket() {
00419 close(_fd);
00420 }
00421
00422 void
00423 NLSocket::send(const NLMessage& m) {
00424 RequestVisitor r;
00425
00426 m.accept(r);
00427
00428
00429
00430 int ret = ::send(_fd, r.buffer(), r.length(), 0);
00431
00432 if (ret < 0 )
00433 throw std::runtime_error(strerror(errno));
00434 }
00435
00436 void
00437 NLSocket::do_receive(char*& buffer, unsigned& length) {
00438 int ret;
00439
00440 do {
00441 if (buffer != 0)
00442 delete[] buffer;
00443
00444 length *= 2;
00445 buffer = new char[length];
00446
00447 ret = recv(_fd, buffer, length, MSG_PEEK);
00448
00449 if (ret < 0)
00450 throw std::runtime_error(strerror(errno));
00451
00452 } while ((unsigned) ret == length);
00453
00454 ret = recv(_fd, buffer, length, 0);
00455
00456 if (ret < 0)
00457 throw std::runtime_error(strerror(errno));
00458
00459 assert((unsigned) ret < length);
00460
00461 length = ret;
00462 }
00463
00464 std::list<NLMessage*>
00465 NLSocket::receive() {
00466 char* buffer = 0;
00467 unsigned length = 2048;
00468 unsigned size = 0;
00469 bool done = true;
00470 std::list<NLMessage*> output;
00471
00472 nlmsghdr* nh = 0;
00473
00474 try {
00475 do {
00476
00477 try {
00478 do_receive(buffer, length);
00479 } catch (std::exception& e) {
00480 if (buffer != 0) {
00481 delete[] buffer;
00482 buffer = 0;
00483 }
00484 throw;
00485 }
00486
00487 size = length;
00488
00489 for (nh = (nlmsghdr*) buffer;
00490 size > 0;
00491 nh = NLMSG_NEXT(nh, size)) {
00492
00493 if (!NLMSG_OK(nh, size))
00494 throw std::runtime_error("Netlink message truncated");
00495
00496 if (nh->nlmsg_flags & NLM_F_MULTI)
00497 done = false;
00498
00499 switch (nh->nlmsg_type) {
00500 case NLMSG_ERROR: {
00501 nlmsgerr* me = (nlmsgerr*) NLMSG_DATA(nh);
00502 if (me->error == 0)
00503 output.push_back(new NLAck);
00504 else
00505 output.push_back(new NLError(-me->error));
00506 }
00507 break;
00508 case NLMSG_DONE:
00509 done = true;
00510 break;
00511 case RTM_NEWLINK: {
00512
00513
00514
00515 done = false;
00516
00517 ifinfomsg* ih = (ifinfomsg*) NLMSG_DATA(nh);
00518 unsigned size = IFLA_PAYLOAD(nh);
00519
00520 NLNewLink* m = new NLNewLink(ih->ifi_family,
00521 ih->ifi_type,
00522 ih->ifi_index,
00523 ih->ifi_flags);
00524
00525 for (rtattr* rt = IFLA_RTA(ih);
00526 size > 0;
00527 rt = RTA_NEXT(rt, size)) {
00528
00529 if (!RTA_OK(rt, size)) {
00530 delete m;
00531 throw std::runtime_error("RTA truncated");
00532 }
00533
00534 switch (rt->rta_type) {
00535 case IFLA_IFNAME:
00536 m->add_attr(new NLLinkAttrName((char*) RTA_DATA(rt)));
00537 break;
00538 case IFLA_MTU:
00539 m->add_attr(new NLLinkAttrMTU(*(unsigned*)RTA_DATA(rt)));
00540 break;
00541 }
00542 }
00543
00544 output.push_back(m);
00545 }
00546 break;
00547
00548 case RTM_NEWADDR: {
00549
00550
00551
00552 done = false;
00553
00554 ifaddrmsg* ia = (ifaddrmsg*) NLMSG_DATA(nh);
00555 unsigned size = IFA_PAYLOAD(nh);
00556
00557 NLNewAddr* m = new NLNewAddr(ia->ifa_family,
00558 ia->ifa_prefixlen,
00559 ia->ifa_flags,
00560 ia->ifa_scope,
00561 ia->ifa_index);
00562
00563 for (rtattr* rt = IFA_RTA(ia);
00564 size > 0;
00565 rt = RTA_NEXT(rt, size)) {
00566 if (!RTA_OK(rt, size)) {
00567 delete m;
00568 throw std::runtime_error("RTA truncated");
00569 }
00570
00571 switch (rt->rta_type) {
00572 case IFA_ADDRESS:
00573 m->add_attr(new NLAddrAttrAddress((unsigned char*)
00574 RTA_DATA(rt),
00575 RTA_PAYLOAD(rt)));
00576 break;
00577 case IFA_LOCAL:
00578 m->add_attr(new NLAddrAttrLocal((unsigned char*)
00579 RTA_DATA(rt),
00580 RTA_PAYLOAD(rt)));
00581 break;
00582 case IFA_LABEL:
00583 m->add_attr(new NLAddrAttrLabel((char*) RTA_DATA(rt)));
00584 break;
00585 case IFA_BROADCAST:
00586 m->add_attr(new NLAddrAttrBroadcast((unsigned char*)
00587 RTA_DATA(rt),
00588 RTA_PAYLOAD(rt)));
00589 break;
00590 case IFA_ANYCAST:
00591 m->add_attr(new NLAddrAttrAnycast((unsigned char*)
00592 RTA_DATA(rt),
00593 RTA_PAYLOAD(rt)));
00594 break;
00595 }
00596 }
00597 output.push_back(m);
00598 }
00599 break;
00600 case RTM_NEWROUTE: {
00601
00602
00603
00604 done = false;
00605
00606 rtmsg* rt = (rtmsg*) NLMSG_DATA(nh);
00607 unsigned size = RTM_PAYLOAD(nh);
00608
00609 NLNewRoute* m = new NLNewRoute(rt->rtm_family,
00610 rt->rtm_dst_len,
00611 rt->rtm_src_len,
00612 rt->rtm_tos,
00613 rt->rtm_table,
00614 rt->rtm_protocol,
00615 rt->rtm_scope,
00616 rt->rtm_type,
00617 rt->rtm_flags);
00618
00619 for (rtattr* ra = RTM_RTA(rt); size > 0;
00620 ra = RTA_NEXT(ra, size)) {
00621 if (!RTA_OK(ra, size)) {
00622 delete m;
00623 throw std::runtime_error("RTA truncated");
00624 }
00625
00626 switch (ra->rta_type) {
00627 case RTA_DST:
00628 m->add_attr(new NLRouteAttrDestination((unsigned char*)
00629 RTA_DATA(ra),
00630 RTA_PAYLOAD(ra)));
00631 break;
00632 case RTA_GATEWAY:
00633 m->add_attr(new NLRouteAttrGateway((unsigned char*)
00634 RTA_DATA(ra),
00635 RTA_PAYLOAD(ra)));
00636 break;
00637 case RTA_OIF:
00638 m->add_attr(new NLRouteAttrOutInterface(*(int*)
00639 RTA_DATA(ra)));
00640 break;
00641 }
00642 }
00643
00644 output.push_back(m);
00645 }
00646 break;
00647 }
00648
00649 }
00650
00651 } while (!done);
00652
00653 } catch (std::exception& e) {
00654 if (buffer != 0)
00655 delete[] buffer;
00656 for (std::list<NLMessage*>::iterator i = output.begin();
00657 i != output.end(); ++i)
00658 delete *i;
00659 throw;
00660 }
00661
00662 if (buffer != 0)
00663 delete[] buffer;
00664
00665 return output;
00666 }
00667
00668 }
00669
00670 }
00671
00672 }
00673
00674 #endif // ! QOLYESTER_SYS_LINUX_NETLINK_HXX