1 /* 2 * Copyright 2015 Steven Barth <steven at midlink.org> 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 #include <errno.h> 19 #include <libubox/list.h> 20 21 #include "querier.h" 22 #include "client.h" 23 #include "mrib.h" 24 #include "proxy.h" 25 26 struct proxy { 27 struct list_head head; 28 int ifindex; 29 struct mrib_user mrib; 30 struct querier querier; 31 enum proxy_flags flags; 32 }; 33 34 struct proxy_downlink { 35 struct querier_user_iface iface; 36 struct mrib_user mrib; 37 struct client client; 38 enum proxy_flags flags; 39 }; 40 41 static struct list_head proxies = LIST_HEAD_INIT(proxies); 42 43 // Remove and cleanup a downlink 44 static void proxy_remove_downlink(struct proxy_downlink *downlink) 45 { 46 mrib_detach_user(&downlink->mrib); 47 querier_detach(&downlink->iface); 48 client_deinit(&downlink->client); 49 free(downlink); 50 } 51 52 // Match scope of a multicast-group against proxy scope-filter 53 static bool proxy_match_scope(enum proxy_flags flags, const struct in6_addr *addr) 54 { 55 unsigned scope = 0; 56 if (IN6_IS_ADDR_V4MAPPED(addr)) { 57 if (addr->s6_addr[12] == 239 && addr->s6_addr[13] == 255) 58 scope = PROXY_REALMLOCAL; 59 else if (addr->s6_addr[12] == 239 && (addr->s6_addr[13] & 0xfc) == 192) 60 scope = PROXY_ORGLOCAL; 61 else if (addr->s6_addr[12] == 224 && addr->s6_addr[13] == 0 && addr->s6_addr[14] == 0) 62 scope = 2; 63 else 64 scope = PROXY_GLOBAL; 65 } else { 66 scope = addr->s6_addr[1] & 0xf; 67 } 68 return scope >= (flags & _PROXY_SCOPEMASK); 69 } 70 71 // Test and set multicast route (called by mrib on detection of new source) 72 static void proxy_mrib(struct mrib_user *mrib, const struct in6_addr *group, 73 const struct in6_addr *source, mrib_filter *filter) 74 { 75 struct proxy *proxy = container_of(mrib, struct proxy, mrib); 76 if (!proxy_match_scope(proxy->flags, group)) 77 return; 78 79 omgp_time_t now = omgp_time(); 80 struct querier_user *user; 81 list_for_each_entry(user, &proxy->querier.ifaces, head) { 82 if (groups_includes_group(user->groups, group, source, now)) { 83 struct querier_user_iface *iface = container_of(user, struct querier_user_iface, user); 84 struct proxy_downlink *downlink = container_of(iface, struct proxy_downlink, iface); 85 mrib_filter_add(filter, &downlink->mrib); 86 } 87 } 88 } 89 90 // Update proxy state (called from querier on change of combined group-state) 91 static void proxy_trigger(struct querier_user_iface *user, const struct in6_addr *group, 92 bool include, const struct in6_addr *sources, size_t len) 93 { 94 struct proxy_downlink *iface = container_of(user, struct proxy_downlink, iface); 95 if (proxy_match_scope(iface->flags, group)) 96 client_set(&iface->client, group, include, sources, len); 97 } 98 99 // Remove proxy with given name 100 static int proxy_unset(struct proxy *proxyp) 101 { 102 bool found = false; 103 struct proxy *proxy, *n; 104 list_for_each_entry_safe(proxy, n, &proxies, head) { 105 if ((proxyp && proxy == proxyp) || 106 (!proxyp && (proxy->flags & _PROXY_UNUSED))) { 107 mrib_detach_user(&proxy->mrib); 108 109 struct querier_user *user, *n; 110 list_for_each_entry_safe(user, n, &proxy->querier.ifaces, head) { 111 struct querier_user_iface *i = container_of(user, struct querier_user_iface, user); 112 proxy_remove_downlink(container_of(i, struct proxy_downlink, iface)); 113 } 114 115 querier_deinit(&proxy->querier); 116 list_del(&proxy->head); 117 free(proxy); 118 found = true; 119 } 120 } 121 return (found) ? 0 : -ENOENT; 122 } 123 124 // Add / update proxy 125 int proxy_set(int uplink, const int downlinks[], size_t downlinks_cnt, enum proxy_flags flags) 126 { 127 struct proxy *proxy = NULL, *p; 128 list_for_each_entry(p, &proxies, head) 129 if (proxy->ifindex == uplink) 130 proxy = p; 131 132 if (proxy && (downlinks_cnt == 0 || 133 ((proxy->flags & _PROXY_SCOPEMASK) != (flags & _PROXY_SCOPEMASK)))) { 134 proxy_unset(proxy); 135 proxy = NULL; 136 } 137 138 if (downlinks_cnt <= 0) 139 return 0; 140 141 if (!proxy) { 142 if (!(proxy = calloc(1, sizeof(*proxy)))) 143 return -ENOMEM; 144 145 if ((flags & _PROXY_SCOPEMASK) == 0) 146 flags |= PROXY_GLOBAL; 147 148 proxy->flags = flags; 149 proxy->ifindex = uplink; 150 querier_init(&proxy->querier); 151 list_add(&proxy->head, &proxies); 152 if (mrib_attach_user(&proxy->mrib, uplink, proxy_mrib)) 153 goto err; 154 } 155 156 struct querier_user *user, *n; 157 list_for_each_entry_safe(user, n, &proxy->querier.ifaces, head) { 158 struct querier_user_iface *iface = container_of(user, struct querier_user_iface, user); 159 160 size_t i; 161 for (i = 0; i < downlinks_cnt && downlinks[i] == iface->iface->ifindex; ++i); 162 if (i == downlinks_cnt) 163 proxy_remove_downlink(container_of(iface, struct proxy_downlink, iface)); 164 } 165 166 for (size_t i = 0; i < downlinks_cnt; ++i) { 167 bool found = false; 168 struct querier_user *user; 169 list_for_each_entry(user, &proxy->querier.ifaces, head) { 170 struct querier_user_iface *iface = container_of(user, struct querier_user_iface, user); 171 if (iface->iface->ifindex == downlinks[i]) { 172 found = true; 173 break; 174 } 175 } 176 177 if (found) 178 continue; 179 180 struct proxy_downlink *downlink = calloc(1, sizeof(*downlink)); 181 if (!downlink) 182 goto err; 183 184 if (client_init(&downlink->client, uplink)) 185 goto downlink_err3; 186 187 if (mrib_attach_user(&downlink->mrib, downlinks[i], NULL)) 188 goto downlink_err2; 189 190 if (querier_attach(&downlink->iface, &proxy->querier, downlinks[i], proxy_trigger)) 191 goto downlink_err1; 192 193 downlink->flags = proxy->flags; 194 continue; 195 196 downlink_err1: 197 mrib_detach_user(&downlink->mrib); 198 downlink_err2: 199 client_deinit(&downlink->client); 200 downlink_err3: 201 free(downlink); 202 goto err; 203 } 204 205 return 0; 206 207 err: 208 proxy_unset(proxy); 209 return -errno; 210 } 211 212 // Mark all flushable proxies as unused 213 void proxy_update(bool all) 214 { 215 struct proxy *proxy; 216 list_for_each_entry(proxy, &proxies, head) 217 if (all || (proxy->flags & PROXY_FLUSHABLE)) 218 proxy->flags |= _PROXY_UNUSED; 219 } 220 221 222 // Flush all unused proxies 223 void proxy_flush(void) 224 { 225 proxy_unset(NULL); 226 } 227
This page was automatically generated by LXR 0.3.1. • OpenWrt