• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/omcproxy/src/proxy.c

  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