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