int ctrl_iface_systemd_socket() { char *env, *ptr; unsigned int p, l; env = getenv("LISTEN_PID"); if (!env) return -1; p = strtoul(env, &ptr, 10); if (ptr && ptr == env) { LLDPAD_DBG("Invalid value '%s' for LISTEN_PID\n", env); return -1; } if ((pid_t)p != getpid()) { LLDPAD_DBG("Invalid PID '%d' from LISTEN_PID\n", p); return -1; } env = getenv("LISTEN_FDS"); if (!env) { LLDPAD_DBG("LISTEN_FDS is not set\n"); return -1; } l = strtoul(env, &ptr, 10); if (ptr && ptr == env) { LLDPAD_INFO("Invalid value '%s' for LISTEN_FDS\n", env); return -1; } if (l != 1) { LLDPAD_INFO("LISTEN_FDS specified %d fds\n", l); return -1; } /* systemd returns fds with an offset of '3' */ return 3; }
int ctrl_iface_init(struct clif_data *clifd) { struct sockaddr_un addr; int s = -1; socklen_t addrlen; const int feature_on = 1; clifd->ctrl_sock = -1; clifd->ctrl_dst = NULL; s = ctrl_iface_systemd_socket(); if (s != -1) { LLDPAD_INFO("using fd %d from systemd\n", s); goto out; } s = socket(AF_LOCAL, SOCK_DGRAM, 0); if (s < 0) { LLDPAD_WARN("failed to create CLI socket: %m\n"); goto fail; } /* enable receiving of the sender credentials */ setsockopt(s, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on)); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_LOCAL; snprintf(&addr.sun_path[1], sizeof(addr.sun_path) - 1, "%s", LLDP_CLIF_SOCK); addrlen = sizeof(sa_family_t) + strlen(addr.sun_path + 1) + 1; if (bind(s, (struct sockaddr *) &addr, addrlen) < 0) { if (errno == EADDRINUSE) LLDPAD_WARN("another lldpad instance is running\n"); else LLDPAD_WARN("failed to bind CLI socket address: %m"); goto fail; } /* enable receiving of the sender credentials */ setsockopt(s, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on)); LLDPAD_INFO("bound ctrl iface to %s\n", &addr.sun_path[1]); out: clifd->ctrl_sock = s; return 0; fail: if (s >= 0) close(s); return -1; }
static void l2_packet_receive(int sock, void *eloop_ctx, UNUSED void *sock_ctx) { struct l2_packet_data *l2 = eloop_ctx; u8 buf[2300]; int res; struct sockaddr_ll ll; socklen_t fromlen; memset(&ll, 0, sizeof(ll)); fromlen = sizeof(ll); res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, &fromlen); if (res < 0) { LLDPAD_INFO("receive if %s ERROR = %d\n", l2->ifname, errno); if (errno != ENETDOWN) perror("l2_packet_receive - recvfrom"); return; } l2->rx_callback(l2->rx_callback_ctx, ll.sll_ifindex, buf, res); }
static void ctrl_iface_receive(int sock, void *eloop_ctx, UNUSED void *sock_ctx) { struct clif_data *clifd = eloop_ctx; char buf[MAX_CLIF_MSGBUF]; struct msghdr smsg; struct cmsghdr *cmsg; struct iovec iov; struct ucred *cred; char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; int res; struct sockaddr_un from; socklen_t fromlen = sizeof(from); char *reply; const int reply_size = MAX_CLIF_MSGBUF; int reply_len; memset(&buf, 0x00, sizeof(buf)); iov.iov_base = buf; iov.iov_len = sizeof(buf) - 1; memset(&smsg, 0x00, sizeof(struct msghdr)); smsg.msg_name = &from; smsg.msg_namelen = fromlen; smsg.msg_iov = &iov; smsg.msg_iovlen = 1; smsg.msg_control = cred_msg; smsg.msg_controllen = sizeof(cred_msg); res = recvmsg(sock, &smsg, 0); if (res < 0) { perror("recvfrom(ctrl_iface)"); return; } cmsg = CMSG_FIRSTHDR(&smsg); fromlen = smsg.msg_namelen; cred = (struct ucred *)CMSG_DATA(cmsg); if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { LLDPAD_INFO("%s: No sender credentials, ignoring\n", __FUNCTION__); sprintf(buf,"R%02x", cmd_bad_params); sendto(sock, buf, 3, 0, (struct sockaddr *) &from, fromlen); return; } if (cred->uid != 0) { LLDPAD_INFO("%s: sender uid=%i, ignoring\n", __FUNCTION__, cred->uid); sprintf(buf,"R%02x", cmd_no_access); sendto(sock, buf, 3, 0, (struct sockaddr *) &from, fromlen); return; } buf[res] = '\0'; /* wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res); */ reply = malloc(reply_size); if (reply == NULL) { sendto(sock, "R01", 3, 0, (struct sockaddr *) &from, fromlen); return; } memset(reply, 0, reply_size); process_clif_cmd(clifd, &from, fromlen, buf, res, reply, reply_size, &reply_len); /* wpa_hexdump_ascii(MSG_DEBUG, "TX ctrl_iface", (u8 *) reply, reply_len); */ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); free(reply); }
struct l2_packet_data * l2_packet_init( const char *ifname, UNUSED const u8 *own_addr, unsigned short protocol, void (*rx_callback)(void *ctx, int ifindex, const u8 *buf, size_t len), void *rx_callback_ctx, int l2_hdr) { struct l2_packet_data *l2; struct ifreq ifr; struct sockaddr_ll ll; l2 = malloc(sizeof(struct l2_packet_data)); if (l2 == NULL) return NULL; memset(l2, 0, sizeof(*l2)); strncpy(l2->ifname, ifname, sizeof(l2->ifname)); l2->rx_callback = rx_callback; l2->rx_callback_ctx = rx_callback_ctx; l2->l2_hdr = l2_hdr; l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, htons(protocol)); if (l2->fd < 0) { perror("socket(PF_PACKET)"); free(l2); return NULL; } strncpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) { perror("ioctl[SIOCGIFINDEX]"); close(l2->fd); free(l2); return NULL; } l2->ifindex = ifr.ifr_ifindex; memset(&ll, 0, sizeof(ll)); ll.sll_family = PF_PACKET; ll.sll_ifindex = ifr.ifr_ifindex; ll.sll_protocol = htons(protocol); if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) { perror("bind[PF_PACKET]"); close(l2->fd); free(l2); return NULL; } /* current hw address */ if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) { perror("ioctl[SIOCGIFHWADDR]"); close(l2->fd); free(l2); return NULL; } memcpy(l2->curr_mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); if (get_perm_hwaddr(ifname, l2->perm_mac_addr, l2->san_mac_addr) != 0) { memcpy(l2->perm_mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); memset(l2->san_mac_addr, 0xff, ETH_ALEN); } LLDPAD_DBG("%s mac:" MACSTR " perm:" MACSTR " san:" MACSTR "\n", ifname, MAC2STR(l2->curr_mac_addr), MAC2STR(l2->perm_mac_addr), MAC2STR(l2->san_mac_addr)); struct packet_mreq mr; memset(&mr, 0, sizeof(mr)); mr.mr_ifindex = l2->ifindex; mr.mr_alen = ETH_ALEN; memcpy(mr.mr_address, &nearest_bridge, ETH_ALEN); mr.mr_type = PACKET_MR_MULTICAST; if (setsockopt(l2->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) { perror("setsockopt nearest_bridge"); close(l2->fd); free(l2); return NULL; } memcpy(mr.mr_address, &nearest_customer_bridge, ETH_ALEN); if (setsockopt(l2->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) perror("setsockopt nearest_customer_bridge"); memcpy(mr.mr_address, &nearest_nontpmr_bridge, ETH_ALEN); if (setsockopt(l2->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) perror("setsockopt nearest_nontpmr_bridge"); int option = 1; int option_size = sizeof(option); if (setsockopt(l2->fd, SOL_PACKET, PACKET_ORIGDEV, &option, option_size) < 0) { perror("setsockopt SOL_PACKET"); close(l2->fd); free(l2); return NULL; } option = TC_PRIO_CONTROL; if ( setsockopt(l2->fd, SOL_SOCKET, SO_PRIORITY, &option, sizeof(option_size)) < 0) { perror("setsockopt SOL_PRIORITY"); close(l2->fd); free(l2); return NULL; } LLDPAD_INFO("%s MAC address is " MACSTR "\n", ifname, MAC2STR(l2->perm_mac_addr)); eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); return l2; }