1/* 2 * Copyright (C) 1999 Yasuhiro Ohara 3 * 4 * This file is part of GNU Zebra. 5 * 6 * GNU Zebra is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2, or (at your option) any 9 * later version. 10 * 11 * GNU Zebra is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with GNU Zebra; see the file COPYING. If not, write to the 18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 * Boston, MA 02111-1307, USA. 20 */ 21 22#include <zebra.h> 23#include "memory.h" 24#include "log.h" 25#include "sockunion.h" 26 27#include "ospf6d.h" 28#include "ospf6_proto.h" 29 30extern int errno; 31extern struct sockaddr_in6 allspfrouters6; 32extern struct sockaddr_in6 alldrouters6; 33extern int ospf6_sock; 34extern struct thread_master *master; 35 36/* iovec functions */ 37void 38iov_clear (struct iovec *iov, size_t iovlen) 39{ 40 int i; 41 for (i = 0; i < iovlen; i++) 42 { 43 iov[i].iov_base = NULL; 44 iov[i].iov_len = 0; 45 } 46} 47 48int 49iov_count (struct iovec *iov) 50{ 51 int i; 52 for (i = 0; iov[i].iov_base; i++) 53 ; 54 return i; 55} 56 57int 58iov_totallen (struct iovec *iov) 59{ 60 int i; 61 int totallen = 0; 62 for (i = 0; iov[i].iov_base; i++) 63 totallen += iov[i].iov_len; 64 return totallen; 65} 66 67void * 68iov_prepend (int mtype, struct iovec *iov, size_t len) 69{ 70 int i, iovlen; 71 void *base; 72 73 base = (void *) XMALLOC (mtype, len); 74 if (!base) 75 { 76 zlog_warn ("Network: iov_prepend failed"); 77 return NULL; 78 } 79 memset (base, 0, len); 80 81 iovlen = iov_count (iov); 82 for (i = iovlen; i; i--) 83 { 84 iov[i].iov_base = iov[i - 1].iov_base; 85 iov[i].iov_len = iov[i - 1].iov_len; 86 } 87 iov[0].iov_base = (char *)base; 88 iov[0].iov_len = len; 89 90 return base; 91} 92 93void * 94iov_append (int mtype, struct iovec *iov, size_t len) 95{ 96 int i; 97 void *base; 98 99 base = (void *)XMALLOC (mtype, len); 100 if (!base) 101 { 102 zlog_warn ("Network: iov_append failed"); 103 return NULL; 104 } 105 memset (base, 0, len); 106 107 /* proceed to the end */ 108 i = iov_count (iov); 109 110 iov[i].iov_base = (char *)base; 111 iov[i].iov_len = len; 112 113 return base; 114} 115 116void * 117iov_attach_last (struct iovec *iov, void *base, size_t len) 118{ 119 int i; 120 i = iov_count (iov); 121 iov[i].iov_base = (char *)base; 122 iov[i].iov_len = len; 123 return base; 124} 125 126void * 127iov_detach_first (struct iovec *iov) 128{ 129 int i, iovlen; 130 void *base; 131 size_t len; 132 133 base = iov[0].iov_base; 134 len = iov[0].iov_len; 135 iovlen = iov_count (iov); 136 for (i = 0; i < iovlen; i++) 137 { 138 iov[i].iov_base = iov[i + 1].iov_base; 139 iov[i].iov_len = iov[i + 1].iov_len; 140 } 141 return base; 142} 143 144int 145iov_free (int mtype, struct iovec *iov, u_int begin, u_int end) 146{ 147 int i; 148 149 for (i = begin; i < end; i++) 150 { 151 XFREE (mtype, iov[i].iov_base); 152 iov[i].iov_base = NULL; 153 iov[i].iov_len = 0; 154 } 155 156 return 0; 157} 158 159void 160iov_trim_head (int mtype, struct iovec *iov) 161{ 162 void *base; 163 164 base = iov_detach_first (iov); 165 XFREE (mtype, base); 166 return; 167} 168 169void 170iov_free_all (int mtype, struct iovec *iov) 171{ 172 int i, end = iov_count (iov); 173 for (i = 0; i < end; i++) 174 { 175 XFREE (mtype, iov[i].iov_base); 176 iov[i].iov_base = NULL; 177 iov[i].iov_len = 0; 178 } 179} 180 181void 182iov_copy_all (struct iovec *dst, struct iovec *src, size_t size) 183{ 184 int i; 185 for (i = 0; i < size; i++) 186 { 187 dst[i].iov_base = src[i].iov_base; 188 dst[i].iov_len = src[i].iov_len; 189 } 190} 191 192 193/* Make ospf6d's server socket. */ 194int 195ospf6_serv_sock () 196{ 197 ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP); 198 if (ospf6_sock < 0) 199 { 200 zlog_warn ("Network: can't create OSPF6 socket."); 201 return -1; 202 } 203 sockopt_reuseaddr (ospf6_sock); 204 205 /* setup global sockaddr_in6, allspf6 & alldr6 for later use */ 206 allspfrouters6.sin6_family = AF_INET6; 207 alldrouters6.sin6_family = AF_INET6; 208#ifdef SIN6_LEN 209 allspfrouters6.sin6_len = sizeof (struct sockaddr_in6); 210 alldrouters6.sin6_len = sizeof (struct sockaddr_in6); 211#endif /* SIN6_LEN */ 212 inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6.sin6_addr); 213 inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6.sin6_addr); 214 215 return 0; 216} 217 218/* returns 0 if succeed, else returns -1 */ 219int 220ospf6_join_allspfrouters (u_int ifindex) 221{ 222 struct ipv6_mreq mreq6; 223 int retval; 224 225 assert (ifindex); 226 mreq6.ipv6mr_interface = ifindex; 227 memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr, 228 sizeof (struct in6_addr)); 229 230 retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 231 &mreq6, sizeof (mreq6)); 232 233 if (retval < 0) 234 zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s", 235 ifindex, strerror (errno)); 236#if 0 237 else 238 zlog_info ("Network: Join AllSPFRouters on ifindex %d", ifindex); 239#endif 240 241 return retval; 242} 243 244void 245ospf6_leave_allspfrouters (u_int ifindex) 246{ 247 struct ipv6_mreq mreq6; 248 249 assert (ifindex); 250 mreq6.ipv6mr_interface = ifindex; 251 memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr, 252 sizeof (struct in6_addr)); 253 254 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, 255 &mreq6, sizeof (mreq6)) < 0) 256 zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s", 257 ifindex, strerror (errno)); 258 else 259 zlog_info ("Network: Leave AllSPFRouters on ifindex %d", ifindex); 260} 261 262void 263ospf6_join_alldrouters (u_int ifindex) 264{ 265 struct ipv6_mreq mreq6; 266 267 assert (ifindex); 268 mreq6.ipv6mr_interface = ifindex; 269 memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr, 270 sizeof (struct in6_addr)); 271 272 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 273 &mreq6, sizeof (mreq6)) < 0) 274 zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s", 275 ifindex, strerror (errno)); 276 else 277 zlog_info ("Network: Join AllDRouters on ifindex %d", ifindex); 278} 279 280void 281ospf6_leave_alldrouters (u_int ifindex) 282{ 283 struct ipv6_mreq mreq6; 284 285 assert (ifindex); 286 mreq6.ipv6mr_interface = ifindex; 287 memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr, 288 sizeof (struct in6_addr)); 289 290 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, 291 &mreq6, sizeof (mreq6)) < 0) 292 zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex); 293 else 294 zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex); 295} 296 297/* setsockopt ReUseAddr to on */ 298void 299ospf6_set_reuseaddr () 300{ 301 u_int on = 0; 302 if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on, 303 sizeof (u_int)) < 0) 304 zlog_warn ("Network: set SO_REUSEADDR failed: %s", strerror (errno)); 305} 306 307/* setsockopt MulticastLoop to off */ 308void 309ospf6_reset_mcastloop () 310{ 311 u_int off = 0; 312 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 313 &off, sizeof (u_int)) < 0) 314 zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s", 315 strerror (errno)); 316} 317 318void 319ospf6_set_pktinfo () 320{ 321 u_int on = 1; 322#ifdef IPV6_RECVPKTINFO /*2292bis-01*/ 323 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, 324 &on, sizeof (u_int)) < 0) 325 zlog_warn ("Network: set IPV6_RECVPKTINFO failed: %s", strerror (errno)); 326#else /*RFC2292*/ 327 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_PKTINFO, 328 &on, sizeof (u_int)) < 0) 329 zlog_warn ("Network: set IPV6_PKTINFO failed: %s", strerror (errno)); 330#endif 331} 332 333void 334ospf6_set_checksum () 335{ 336 int offset = 12; 337#ifndef DISABLE_IPV6_CHECKSUM 338 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM, 339 &offset, sizeof (offset)) < 0) 340 zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", strerror (errno)); 341#else 342 zlog_warn ("Network: Don't set IPV6_CHECKSUM"); 343#endif /* DISABLE_IPV6_CHECKSUM */ 344} 345 346void 347ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, 348 unsigned int *ifindex, struct iovec *message) 349{ 350 int retval; 351 struct msghdr smsghdr; 352 struct cmsghdr *scmsgp; 353 u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; 354 struct in6_pktinfo *pktinfo; 355 struct sockaddr_in6 dst_sin6; 356 357 assert (dst); 358 assert (*ifindex); 359 360 scmsgp = (struct cmsghdr *)cmsgbuf; 361 pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); 362 memset (&dst_sin6, 0, sizeof (struct sockaddr_in6)); 363 364 /* source address */ 365 pktinfo->ipi6_ifindex = *ifindex; 366 if (src) 367 memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr)); 368 else 369 memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr)); 370 371 /* destination address */ 372 dst_sin6.sin6_family = AF_INET6; 373#ifdef SIN6_LEN 374 dst_sin6.sin6_len = sizeof (struct sockaddr_in6); 375#endif /*SIN6_LEN*/ 376 memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr)); 377#ifdef HAVE_SIN6_SCOPE_ID 378 dst_sin6.sin6_scope_id = *ifindex; 379#endif 380 381 /* send control msg */ 382 scmsgp->cmsg_level = IPPROTO_IPV6; 383 scmsgp->cmsg_type = IPV6_PKTINFO; 384 scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); 385 /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */ 386 387 /* send msg hdr */ 388 smsghdr.msg_iov = message; 389 smsghdr.msg_iovlen = iov_count (message); 390 smsghdr.msg_name = (caddr_t) &dst_sin6; 391 smsghdr.msg_namelen = sizeof (struct sockaddr_in6); 392 smsghdr.msg_control = (caddr_t) cmsgbuf; 393 smsghdr.msg_controllen = sizeof (cmsgbuf); 394 395 retval = sendmsg (ospf6_sock, &smsghdr, 0); 396 if (retval != iov_totallen (message)) 397 zlog_warn ("Network: sendmsg (ifindex: %d) failed: %s(%d)", 398 *ifindex, strerror (errno), errno); 399} 400 401void 402ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst, 403 unsigned int *ifindex, struct iovec *message) 404{ 405 int retval; 406 struct msghdr rmsghdr; 407 struct cmsghdr *rcmsgp; 408 u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; 409 struct in6_pktinfo *pktinfo; 410 struct sockaddr_in6 src_sin6; 411 412 rcmsgp = (struct cmsghdr *)cmsgbuf; 413 pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp)); 414 memset (&src_sin6, 0, sizeof (struct sockaddr_in6)); 415 416 /* receive control msg */ 417 rcmsgp->cmsg_level = IPPROTO_IPV6; 418 rcmsgp->cmsg_type = IPV6_PKTINFO; 419 rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); 420 /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */ 421 422 /* receive msg hdr */ 423 rmsghdr.msg_iov = message; 424 rmsghdr.msg_iovlen = iov_count (message); 425 rmsghdr.msg_name = (caddr_t) &src_sin6; 426 rmsghdr.msg_namelen = sizeof (struct sockaddr_in6); 427 rmsghdr.msg_control = (caddr_t) cmsgbuf; 428 rmsghdr.msg_controllen = sizeof (cmsgbuf); 429 430 retval = recvmsg (ospf6_sock, &rmsghdr, 0); 431 if (retval < 0) 432 { 433 zlog_warn ("Network: recvmsg failed: %s", strerror (errno)); 434 } 435 else if (retval == iov_totallen (message)) 436 { 437 zlog_warn ("Network: possibly buffer shortage: %d received, buffer size: %d", 438 retval, iov_totallen (message)); 439 } 440 441 /* source address */ 442 assert (src); 443 memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr)); 444 445 /* destination address */ 446 if (ifindex) 447 *ifindex = pktinfo->ipi6_ifindex; 448 if (dst) 449 memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr)); 450} 451 452void 453ospf6_recvmsg_peek (struct in6_addr *src, struct in6_addr *dst, 454 unsigned int *ifindex, struct iovec *message) 455{ 456 int retval; 457 struct msghdr rmsghdr; 458 struct cmsghdr *rcmsgp; 459 u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; 460 struct in6_pktinfo *pktinfo; 461 struct sockaddr_in6 src_sin6; 462 463 rcmsgp = (struct cmsghdr *)cmsgbuf; 464 pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp)); 465 memset (&src_sin6, 0, sizeof (struct sockaddr_in6)); 466 467 /* receive control msg */ 468 rcmsgp->cmsg_level = IPPROTO_IPV6; 469 rcmsgp->cmsg_type = IPV6_PKTINFO; 470 rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); 471 /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */ 472 473 /* receive msg hdr */ 474 rmsghdr.msg_iov = message; 475 rmsghdr.msg_iovlen = iov_count (message); 476 rmsghdr.msg_name = (caddr_t) &src_sin6; 477 rmsghdr.msg_namelen = sizeof (struct sockaddr_in6); 478 rmsghdr.msg_control = (caddr_t) cmsgbuf; 479 rmsghdr.msg_controllen = sizeof (cmsgbuf); 480 481 retval = recvmsg (ospf6_sock, &rmsghdr, MSG_PEEK); 482 if (retval != iov_totallen (message)) 483 zlog_warn ("Network: recvmsg failed: %s", strerror (errno)); 484 485 /* source address */ 486 assert (src); 487 memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr)); 488 489 /* destination address */ 490 if (ifindex) 491 *ifindex = pktinfo->ipi6_ifindex; 492 if (dst) 493 memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr)); 494} 495 496