static int bfd_ioctl_state_change (struct bfd_nl_peerinfo *peerinfo) { struct bfd_peer peer; struct zserv *client; struct listnode *node; if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("rcvd peerinfo %s: state=%d, ifindex=%d", sockunion_log ((union sockunion *) &peerinfo->dst), peerinfo->state, peerinfo->ifindex); memcpy (&peer.su, &peerinfo->dst.sa, sizeof (union sockunion)); peer.ifindex = peerinfo->ifindex; if (peerinfo->state == BSM_Up) { for (node = listhead (client_list); node; nextnode (node)) if ((client = getdata (node)) != NULL) zsend_bfd_peer_up (client, &peer); } else if (peerinfo->state == BSM_Down) { for (node = listhead (client_list); node; nextnode (node)) if ((client = getdata (node)) != NULL) zsend_bfd_peer_down (client, &peer); } else { } return 0; }
/* sockunion_connect returns -1 : error occured 0 : connect success 1 : connect is in progress */ enum connect_result sockunion_connect (int fd, union sockunion *peersu, unsigned short port, unsigned int ifindex) { int ret; int val = 1; union sockunion su; //inet_ntop(AF_INET, &sin.sin_addr, buf, 256); //fprintf(stderr, "convert from dstip %s address to union address success\n", buf); memcpy(&su, peersu, sizeof(union sockunion)); printf ( "try connect to %s:%d fd %d : %s",sockunion_log ( &su ), ntohs(port), fd, strerror ( errno ) ); /* Call connect function. */ ret = connect(fd, (struct sockaddr *) &su, sockunion_sizeof(&su)); val = 0; /* added by fanky 2004 0601 */ /* Immediate success */ if (ret == 0) { ret = ioctl(fd, FIONBIO, &val); return connect_success; } /* If connect is in progress then return 1 else it's real error. */ if (ret < 0) { if (errno != EINPROGRESS) { printf ( "can't connect to %s fd %d : %s", sockunion_log ( &su ), fd, strerror ( errno ) ); return connect_error; } } return connect_in_progress; }
/* Return socket of sockunion. */ int sockunion_socket(const union sockunion *su) { int sock; sock = socket(su->sa.sa_family, SOCK_STREAM, 0); if (sock < 0) { char buf[SU_ADDRSTRLEN]; zlog_warn("Can't make socket for %s : %s", sockunion_log(su, buf, SU_ADDRSTRLEN), safe_strerror(errno)); return -1; } return sock; }
/* Performs a non-blocking connect(). */ enum connect_result sockunion_connect(int fd, const union sockunion *peersu, unsigned short port, ifindex_t ifindex) { int ret; union sockunion su; memcpy(&su, peersu, sizeof(union sockunion)); switch (su.sa.sa_family) { case AF_INET: su.sin.sin_port = port; break; case AF_INET6: su.sin6.sin6_port = port; #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) { su.sin6.sin6_scope_id = ifindex; SET_IN6_LINKLOCAL_IFINDEX(su.sin6.sin6_addr, ifindex); } #endif /* KAME */ break; } /* Call connect function. */ ret = connect(fd, (struct sockaddr *)&su, sockunion_sizeof(&su)); /* Immediate success */ if (ret == 0) return connect_success; /* If connect is in progress then return 1 else it's real error. */ if (ret < 0) { if (errno != EINPROGRESS) { char str[SU_ADDRSTRLEN]; zlog_info("can't connect to %s fd %d : %s", sockunion_log(&su, str, sizeof str), fd, safe_strerror(errno)); return connect_error; } } return connect_in_progress; }
/* Bind socket to specified address. */ int sockunion_bind(int sock, union sockunion *su, unsigned short port, union sockunion *su_addr) { int size = 0; int ret; if (su->sa.sa_family == AF_INET) { size = sizeof(struct sockaddr_in); su->sin.sin_port = htons(port); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN su->sin.sin_len = size; #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ if (su_addr == NULL) sockunion2ip(su) = htonl(INADDR_ANY); } else if (su->sa.sa_family == AF_INET6) { size = sizeof(struct sockaddr_in6); su->sin6.sin6_port = htons(port); #ifdef SIN6_LEN su->sin6.sin6_len = size; #endif /* SIN6_LEN */ if (su_addr == NULL) { #ifdef LINUX_IPV6 memset(&su->sin6.sin6_addr, 0, sizeof(struct in6_addr)); #else su->sin6.sin6_addr = in6addr_any; #endif /* LINUX_IPV6 */ } } ret = bind(sock, (struct sockaddr *)su, size); if (ret < 0) { char buf[SU_ADDRSTRLEN]; zlog_warn("can't bind socket for %s : %s", sockunion_log(su, buf, SU_ADDRSTRLEN), safe_strerror(errno)); } return ret; }
/* User=>Kernel IOCTL message */ static int bfd_ioctl_peer (int cmd, struct bfd_peer *peer) { int ret; int size; struct bfd_nl_peerinfo req; if(bfd_ioctl_sock < 0) return -1; if (peer->su.sa.sa_family == AF_INET) size = sizeof (struct sockaddr_in); else if (peer->su.sa.sa_family == AF_INET6) size = sizeof (struct sockaddr_in6); else { zlog_warn ("peer sockaddr is invalid"); return -1; } memcpy (&req.dst.sa, &peer->su, size); req.ifindex = peer->ifindex; ret = ioctl(bfd_ioctl_sock, cmd, &req); if (ret == -1) { zlog_warn ("ioctl %s", strerror(errno)); return -1; } if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("bfd peer %s (%s)", cmd == BFD_NEWPEER ? "BFD_NEWPEER" : "BFD_DELPEER", sockunion_log (&peer->su)); return 0; }
/* sockunion_connect returns -1 : error occured 0 : connect success 1 : connect is in progress */ enum connect_result sockunion_connect (int fd, union sockunion *peersu, unsigned short port, unsigned int ifindex) { int ret; int val; union sockunion su; memcpy (&su, peersu, sizeof (union sockunion)); switch (su.sa.sa_family) { case AF_INET: su.sin.sin_port = port; break; #ifdef HAVE_IPV6 case AF_INET6: su.sin6.sin6_port = port; #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) { #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID /* su.sin6.sin6_scope_id = ifindex; */ #ifdef MUSICA su.sin6.sin6_scope_id = ifindex; #endif #endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */ #ifndef MUSICA SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex); #endif } #endif /* KAME */ break; #endif /* HAVE_IPV6 */ } /* Make socket non-block. */ val = fcntl (fd, F_GETFL, 0); fcntl (fd, F_SETFL, val|O_NONBLOCK); /* Call connect function. */ ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su)); /* Immediate success */ if (ret == 0) { fcntl (fd, F_SETFL, val); return connect_success; } /* If connect is in progress then return 1 else it's real error. */ if (ret < 0) { if (errno != EINPROGRESS) { char str[SU_ADDRSTRLEN]; zlog_info ("can't connect to %s fd %d : %s", sockunion_log (&su, str, sizeof str), fd, safe_strerror (errno)); return connect_error; } } fcntl (fd, F_SETFL, val); return connect_in_progress; }
/* sockunion_connect returns -1 : error occured 0 : connect success 1 : connect is in progress */ enum connect_result sockunion_connect (int fd, union sockunion *peersu, unsigned short port, unsigned int ifindex) { int ret; int val; union sockunion su; int ret2=0; memcpy (&su, peersu, sizeof (union sockunion)); switch (su.sa.sa_family) { case AF_INET: su.sin.sin_port = port; break; #ifdef HAVE_IPV6 case AF_INET6: su.sin6.sin6_port = port; #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) { #ifdef HAVE_SIN6_SCOPE_ID /* su.sin6.sin6_scope_id = ifindex; */ #ifdef MUSICA su.sin6.sin6_scope_id = ifindex; #endif #endif /* HAVE_SIN6_SCOPE_ID */ #ifndef MUSICA SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex); #endif } #endif /* KAME */ break; #endif /* HAVE_IPV6 */ } /* Make socket non-block. */ val = fcntl (fd, F_GETFL, 0); /*CID 10316 (#1 of 3): Unchecked return value from library (CHECKED_RETURN) 3. check_return: Calling function "fcntl(fd, 4, val | 0x80)" without checking return value. This library function may fail and return an error code. Add check return value.*/ /*fcntl (fd, F_SETFL, val|O_NONBLOCK);*/ ret = fcntl (fd, F_SETFL, val|O_NONBLOCK); if(ret < 0) zlog_warn("%s: line %d, fcntl failed : %s .\n",__func__,__LINE__,safe_strerror(errno)); /* Call connect function. */ ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su)); /* Immediate success */ if (ret == 0) { /*CID 10316 (#2 of 3): Unchecked return value from library (CHECKED_RETURN) 4. check_return: Calling function "fcntl(fd, 4, val)" without checking return value. This library function may fail and return an error code. Change , add check return value.*/ /*fcntl (fd, F_SETFL, val);*/ ret2 = fcntl (fd, F_SETFL, val); if(ret < 0) zlog_warn("%s: line %d, fcntl failed : %s .\n",__func__,__LINE__,safe_strerror(errno)); return connect_success; } /* If connect is in progress then return 1 else it's real error. */ if (ret < 0) { if (errno != EINPROGRESS) { char *log_str = sockunion_log (&su); zlog_info ("can't connect to %s fd %d : %s", log_str, fd, safe_strerror (errno)); free(log_str); return connect_error; } } /*CID 10316 (#3 of 3): Unchecked return value from library (CHECKED_RETURN) 6. check_return: Calling function "fcntl(fd, 4, val)" without checking return value. This library function may fail and return an error code. Add check return value.*/ /*fcntl (fd, F_SETFL, val);*/ ret2 = fcntl (fd, F_SETFL, val); if(ret < 0) zlog_warn("%s: line %d, fcntl failed : %s .\n",__func__,__LINE__,safe_strerror(errno)); return connect_in_progress; }