static int local_service_generic(struct hostctrl *hc, int type, const struct service_id *srvid, unsigned short prefix_bits, unsigned int priority, unsigned int weight, const struct in_addr *ipaddr) { struct { struct ctrlmsg_service cm; struct service_info service; } req; if (!srvid) return -1; memset(&req, 0, sizeof(req)); req.cm.cmh.type = type; req.cm.cmh.xid = ++hc->xid; req.cm.cmh.len = CTRLMSG_SERVICE_NUM_LEN(1); req.cm.service[0].srvid_prefix_bits = (prefix_bits > SERVICE_ID_MAX_PREFIX_BITS) ? 0 : prefix_bits; req.cm.service[0].priority = priority; req.cm.service[0].weight = weight; memcpy(&req.cm.service[0].srvid, srvid, sizeof(*srvid)); if (ipaddr) memcpy(&req.cm.service[0].address, ipaddr, sizeof(*ipaddr)); req.cm.service[0].if_index = -1; /* strncpy(req.cm.ifname, ifname, IFNAMSIZ - 1); */ LOG_DBG("op=%d prefix_bits=%u len=%u sizeof(req)=%zu %zu %s\n", type, req.cm.service[0].srvid_prefix_bits, CTRLMSG_SERVICE_LEN(&req.cm), sizeof(req), CTRLMSG_SERVICE_NUM(&req.cm), service_id_to_str(&req.cm.service[0].srvid)); return message_channel_send(hc->mc, &req.cm, req.cm.cmh.len); }
int local_ctrlmsg_recv(struct hostctrl *hc, struct ctrlmsg *cm, struct sockaddr *from, socklen_t from_len) { struct in_addr local_ip; int ret = 0; if (!hc->cbs) return 0; memset(&local_ip, 0, sizeof(local_ip)); if (from) { if (from->sa_family == AF_INET) memcpy(&local_ip, &((struct sockaddr_in *)from)->sin_addr, sizeof(local_ip)); else if (from->sa_family == AF_SERVAL && from_len > sizeof(struct sockaddr_in)) { channel_addr_t *addr = (channel_addr_t *)from; if (addr->sv_in.in.sin_family == AF_INET) { memcpy(&local_ip, &addr->sv_in.in.sin_addr, sizeof(local_ip)); } } } switch (cm->type) { case CTRLMSG_TYPE_REGISTER: { struct ctrlmsg_register *cmr = (struct ctrlmsg_register *)cm; ret = hc->cbs->service_registration(hc, &cmr->srvid, cmr->srvid_flags, cmr->srvid_prefix_bits, &local_ip, NULL); break; } case CTRLMSG_TYPE_UNREGISTER: { struct ctrlmsg_register *cmr = (struct ctrlmsg_register *)cm; ret = hc->cbs->service_unregistration(hc, &cmr->srvid, cmr->srvid_flags, cmr->srvid_prefix_bits, &local_ip); break; } case CTRLMSG_TYPE_RESOLVE: break; case CTRLMSG_TYPE_GET_SERVICE: { struct ctrlmsg_service *cs = (struct ctrlmsg_service *)cm; if (hc->cbs->service_get_result) ret = hc->cbs->service_get_result(hc, cm->xid, cm->retval, &cs->service[0], CTRLMSG_SERVICE_NUM(cs)); break; } case CTRLMSG_TYPE_SERVICE_STAT: { struct ctrlmsg_service_stat *css = (struct ctrlmsg_service_stat *)cm; if (hc->cbs->service_stat_update) ret = hc->cbs->service_stat_update(hc, cm->xid, cm->retval, &css->stats, CTRLMSG_SERVICE_STAT_NUM(css)); break; } case CTRLMSG_TYPE_ADD_SERVICE: { struct ctrlmsg_service *cs = (struct ctrlmsg_service *)cm; if (hc->cbs->service_add_result) ret = hc->cbs->service_add_result(hc, cm->xid, cm->retval, &cs->service[0], CTRLMSG_SERVICE_NUM(cs)); break; } case CTRLMSG_TYPE_MOD_SERVICE: { struct ctrlmsg_service *cs = (struct ctrlmsg_service *)cm; if (hc->cbs->service_mod_result) ret = hc->cbs->service_mod_result(hc, cm->xid, cm->retval, &cs->service[0], CTRLMSG_SERVICE_NUM(cs)); break; } case CTRLMSG_TYPE_DEL_SERVICE: { struct ctrlmsg_service_info_stat *csis = (struct ctrlmsg_service_info_stat *)cm; if (hc->cbs->service_remove_result) ret = hc->cbs->service_remove_result(hc, cm->xid, cm->retval, &csis->service[0], CTRLMSG_SERVICE_INFO_STAT_NUM(csis)); break; } default: LOG_DBG("Received message type %u\n", cm->type); break; } return ret; }
static int ctrl_handle_mod_service_msg(struct ctrlmsg *cm, int peer) { struct ctrlmsg_service *cmr = (struct ctrlmsg_service *)cm; unsigned int num_res = CTRLMSG_SERVICE_NUM(cmr); unsigned int i, index = 0; int err = 0; if (num_res < 2 || num_res % 2 != 0) { LOG_DBG("Not an even number of service infos\n"); return 0; } LOG_DBG("modifying %u services\n", num_res / 2); for (i = 0; i < num_res; i += 2) { struct net_device *dev; struct service_info *entry_old = &cmr->service[i]; struct service_info *entry_new = &cmr->service[i+1]; unsigned short prefix_bits = SERVICE_ID_MAX_PREFIX_BITS; if (entry_old->srvid_prefix_bits > 0) prefix_bits = entry_old->srvid_prefix_bits; #if defined(ENABLE_DEBUG) { char buf[18]; LOG_DBG("Modifying: %s flags(%i) bits(%i) %s\n", service_id_to_str(&entry_old->srvid), entry_old->srvid_flags, prefix_bits, inet_ntop(AF_INET, &entry_old->address, buf, 18)); } #endif dev = resolve_dev(entry_old); if (!dev) continue; err = service_modify(&entry_old->srvid, prefix_bits, SERVICE_RULE_FORWARD, entry_old->srvid_flags, entry_new->priority, entry_new->weight, &entry_old->address, sizeof(entry_old->address), &entry_new->address, sizeof(entry_new->address), make_target(dev)); if (err > 0) { if (index < i) { /* copy it over */ memcpy(&cmr->service[index], entry_new, sizeof(*entry_new)); } index++; } else { LOG_ERR("Could not modify service %s: %i\n", service_id_to_str(&entry_old->srvid), err); } dev_put(dev); } if (index == 0) { cm->retval = CTRLMSG_RETVAL_NOENTRY; } else { cm->retval = CTRLMSG_RETVAL_OK; cm->len = CTRLMSG_SERVICE_NUM_LEN(index); } ctrl_sendmsg(cm, peer, GFP_KERNEL); return 0; }
static int ctrl_handle_add_service_msg(struct ctrlmsg *cm, int peer) { struct ctrlmsg_service *cmr = (struct ctrlmsg_service *)cm; unsigned int num_res = CTRLMSG_SERVICE_NUM(cmr); /* TODO - flags, etc */ unsigned int i, index = 0; int err = 0; LOG_DBG("adding %u services, msg size %u\n", num_res, CTRLMSG_SERVICE_LEN(cmr)); for (i = 0; i < num_res; i++) { struct net_device *dev = NULL; struct service_info *entry = &cmr->service[i]; unsigned short prefix_bits = SERVICE_ID_MAX_PREFIX_BITS; if (entry->type == SERVICE_RULE_FORWARD) { dev = resolve_dev(entry); if (!dev) continue; } if (entry->srvid_prefix_bits > 0) prefix_bits = entry->srvid_prefix_bits; #if defined(ENABLE_DEBUG) { char ipstr[18]; LOG_DBG("Adding service id: %s(%u) " "@ address %s, priority %u, weight %u\n", service_id_to_str(&entry->srvid), prefix_bits, inet_ntop(AF_INET, &entry->address, ipstr, sizeof(ipstr)), entry->priority, entry->weight); } #endif err = service_add(&entry->srvid, prefix_bits, entry->type, entry->srvid_flags, entry->priority, entry->weight, &entry->address, sizeof(entry->address), make_target(dev), GFP_KERNEL); if (dev) dev_put(dev); if (err > 0) { if (index < i) { /* copy it over */ memcpy(&cmr->service[index], entry, sizeof(*entry)); } index++; } else { LOG_ERR("Error adding service %s: err=%d\n", service_id_to_str(&entry->srvid), err); } } if (index == 0) { /* Just return the original request with a return value */ cm->retval = CTRLMSG_RETVAL_NOENTRY; } else { /* Return the entries added */ cm->retval = CTRLMSG_RETVAL_OK; cm->len = CTRLMSG_SERVICE_NUM_LEN(index); } ctrl_sendmsg(cm, peer, GFP_KERNEL); return 0; }
static int ctrl_handle_del_service_msg(struct ctrlmsg *cm, int peer) { struct ctrlmsg_service *cmr = (struct ctrlmsg_service *)cm; unsigned int num_res = CTRLMSG_SERVICE_NUM(cmr); const size_t cmsg_size = sizeof(struct ctrlmsg_service_info_stat) + sizeof(struct service_info_stat) * num_res; struct ctrlmsg_service_info_stat *cms; struct service_id null_service = { .s_sid = { 0 } }; unsigned int i = 0, index = 0; int err = 0; LOG_DBG("deleting %u services\n", num_res); cms = kmalloc(cmsg_size, GFP_KERNEL); if (!cms) { cm->retval = CTRLMSG_RETVAL_ERROR; ctrl_sendmsg(cm, peer, GFP_KERNEL); return -ENOMEM; } memset(cms, 0, cmsg_size); for (i = 0; i < num_res; i++) { struct service_info *entry = &cmr->service[i]; struct service_info_stat *stat = &cms->service[index]; struct target_stats tstat; struct service_entry *se; unsigned short prefix_bits = SERVICE_ID_MAX_PREFIX_BITS; /* We might be trying to delete the "default" entry. In that case */ if (memcmp(&entry->srvid, &null_service, sizeof(null_service)) == 0 || entry->srvid_prefix_bits > 0) prefix_bits = entry->srvid_prefix_bits; stat->service.srvid_prefix_bits = prefix_bits; se = service_find_exact(&entry->srvid, prefix_bits); if (!se) { LOG_DBG("No match for serviceID %s:(%u)\n", service_id_to_str(&entry->srvid), prefix_bits); continue; } memset(&tstat, 0, sizeof(tstat)); err = service_entry_remove_target(se, entry->type, &entry->address, sizeof(entry->address), &tstat); if (err > 0) { stat->duration_sec = tstat.duration_sec; stat->duration_nsec = tstat.duration_nsec; stat->packets_resolved = tstat.packets_resolved; stat->bytes_resolved = tstat.bytes_resolved; stat->packets_dropped = tstat.packets_dropped; stat->bytes_dropped = tstat.packets_dropped; //if (index < i) { memcpy(&stat->service, entry, sizeof(*entry)); //} LOG_DBG("Service ID %s:%u\n", service_id_to_str(&stat->service.srvid), stat->service.srvid_prefix_bits); index++; } else if (err == 0) { LOG_ERR("Could not find target for service %s\n", service_id_to_str(&entry->srvid)); } else { LOG_ERR("Could not remove service %s - err %d\n", service_id_to_str(&entry->srvid), err); } service_entry_put(se); } if (index == 0) { cm->retval = CTRLMSG_RETVAL_NOENTRY; ctrl_sendmsg(cm, peer, GFP_KERNEL); } else { cms->cmh.type = CTRLMSG_TYPE_DEL_SERVICE; cms->xid = cmr->xid; cms->cmh.xid = cm->xid; cms->cmh.retval = CTRLMSG_RETVAL_OK; cms->cmh.len = CTRLMSG_SERVICE_INFO_STAT_NUM_LEN(index); ctrl_sendmsg(&cms->cmh, peer, GFP_KERNEL); } kfree(cms); return 0; }