| 1240 | } |
| 1241 | |
| 1242 | static int |
| 1243 | vxlan_socket_mc_add_group(struct vxlan_socket *vso, |
| 1244 | const union vxlan_sockaddr *group, const union vxlan_sockaddr *local, |
| 1245 | int ifidx, int *idx) |
| 1246 | { |
| 1247 | union vxlan_sockaddr source; |
| 1248 | struct vxlan_socket_mc_info *mc; |
| 1249 | int i, empty, error; |
| 1250 | |
| 1251 | /* |
| 1252 | * Within a socket, the same multicast group may be used by multiple |
| 1253 | * interfaces, each with a different network identifier. But a socket |
| 1254 | * may only join a multicast group once, so keep track of the users |
| 1255 | * here. |
| 1256 | */ |
| 1257 | |
| 1258 | VXLAN_SO_WLOCK(vso); |
| 1259 | for (empty = 0, i = 0; i < VXLAN_SO_MC_MAX_GROUPS; i++) { |
| 1260 | mc = &vso->vxlso_mc[i]; |
| 1261 | |
| 1262 | if (mc->vxlsomc_gaddr.sa.sa_family == AF_UNSPEC) { |
| 1263 | empty++; |
| 1264 | continue; |
| 1265 | } |
| 1266 | |
| 1267 | if (vxlan_sockaddr_mc_info_match(mc, group, local, ifidx)) |
| 1268 | goto out; |
| 1269 | } |
| 1270 | VXLAN_SO_WUNLOCK(vso); |
| 1271 | |
| 1272 | if (empty == 0) |
| 1273 | return (ENOSPC); |
| 1274 | |
| 1275 | error = vxlan_socket_mc_join_group(vso, group, local, &ifidx, &source); |
| 1276 | if (error) |
| 1277 | return (error); |
| 1278 | |
| 1279 | VXLAN_SO_WLOCK(vso); |
| 1280 | for (i = 0; i < VXLAN_SO_MC_MAX_GROUPS; i++) { |
| 1281 | mc = &vso->vxlso_mc[i]; |
| 1282 | |
| 1283 | if (mc->vxlsomc_gaddr.sa.sa_family == AF_UNSPEC) { |
| 1284 | vxlan_sockaddr_copy(&mc->vxlsomc_gaddr, &group->sa); |
| 1285 | vxlan_sockaddr_copy(&mc->vxlsomc_saddr, &source.sa); |
| 1286 | mc->vxlsomc_ifidx = ifidx; |
| 1287 | goto out; |
| 1288 | } |
| 1289 | } |
| 1290 | VXLAN_SO_WUNLOCK(vso); |
| 1291 | |
| 1292 | error = vxlan_socket_mc_leave_group(vso, group, &source, ifidx); |
| 1293 | MPASS(error == 0); |
| 1294 | |
| 1295 | return (ENOSPC); |
| 1296 | |
| 1297 | out: |
| 1298 | mc->vxlsomc_users++; |
| 1299 | VXLAN_SO_WUNLOCK(vso); |
no test coverage detected