|
54 | 54 | #include "hash.h"
|
55 | 55 | #include "log.h"
|
56 | 56 | #include "netlink.h"
|
| 57 | +#include "send.h" |
57 | 58 | #include "soft-interface.h"
|
58 | 59 | #include "translation-table.h"
|
59 | 60 | #include "tvlv.h"
|
@@ -979,6 +980,7 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
979 | 980 | {
|
980 | 981 | int ret, tt_count, ip_count, unsnoop_count, total_count;
|
981 | 982 | bool is_unsnoopable = false;
|
| 983 | + unsigned int mcast_fanout; |
982 | 984 | struct ethhdr *ethhdr;
|
983 | 985 |
|
984 | 986 | ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable);
|
@@ -1013,8 +1015,203 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
1013 | 1015 | case 0:
|
1014 | 1016 | return BATADV_FORW_NONE;
|
1015 | 1017 | default:
|
1016 |
| - return BATADV_FORW_ALL; |
| 1018 | + mcast_fanout = atomic_read(&bat_priv->multicast_fanout); |
| 1019 | + |
| 1020 | + if (!unsnoop_count && total_count <= mcast_fanout) |
| 1021 | + return BATADV_FORW_SOME; |
| 1022 | + } |
| 1023 | + |
| 1024 | + return BATADV_FORW_ALL; |
| 1025 | +} |
| 1026 | + |
| 1027 | +/** |
| 1028 | + * batadv_mcast_forw_tt() - forwards a packet to multicast listeners |
| 1029 | + * @bat_priv: the bat priv with all the soft interface information |
| 1030 | + * @skb: the multicast packet to transmit |
| 1031 | + * @vid: the vlan identifier |
| 1032 | + * |
| 1033 | + * Sends copies of a frame with multicast destination to any multicast |
| 1034 | + * listener registered in the translation table. A transmission is performed |
| 1035 | + * via a batman-adv unicast packet for each such destination node. |
| 1036 | + * |
| 1037 | + * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS |
| 1038 | + * otherwise. |
| 1039 | + */ |
| 1040 | +static int |
| 1041 | +batadv_mcast_forw_tt(struct batadv_priv *bat_priv, struct sk_buff *skb, |
| 1042 | + unsigned short vid) |
| 1043 | +{ |
| 1044 | + int ret = NET_XMIT_SUCCESS; |
| 1045 | + struct sk_buff *newskb; |
| 1046 | + |
| 1047 | + struct batadv_tt_orig_list_entry *orig_entry; |
| 1048 | + |
| 1049 | + struct batadv_tt_global_entry *tt_global; |
| 1050 | + const u8 *addr = eth_hdr(skb)->h_dest; |
| 1051 | + |
| 1052 | + tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); |
| 1053 | + if (!tt_global) |
| 1054 | + goto out; |
| 1055 | + |
| 1056 | + rcu_read_lock(); |
| 1057 | + hlist_for_each_entry_rcu(orig_entry, &tt_global->orig_list, list) { |
| 1058 | + newskb = skb_copy(skb, GFP_ATOMIC); |
| 1059 | + if (!newskb) { |
| 1060 | + ret = NET_XMIT_DROP; |
| 1061 | + break; |
| 1062 | + } |
| 1063 | + |
| 1064 | + batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0, |
| 1065 | + orig_entry->orig_node, vid); |
| 1066 | + } |
| 1067 | + rcu_read_unlock(); |
| 1068 | + |
| 1069 | + batadv_tt_global_entry_put(tt_global); |
| 1070 | + |
| 1071 | +out: |
| 1072 | + return ret; |
| 1073 | +} |
| 1074 | + |
| 1075 | +/** |
| 1076 | + * batadv_mcast_forw_want_all_ipv4() - forward to nodes with want-all-ipv4 |
| 1077 | + * @bat_priv: the bat priv with all the soft interface information |
| 1078 | + * @skb: the multicast packet to transmit |
| 1079 | + * @vid: the vlan identifier |
| 1080 | + * |
| 1081 | + * Sends copies of a frame with multicast destination to any node with a |
| 1082 | + * BATADV_MCAST_WANT_ALL_IPV4 flag set. A transmission is performed via a |
| 1083 | + * batman-adv unicast packet for each such destination node. |
| 1084 | + * |
| 1085 | + * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS |
| 1086 | + * otherwise. |
| 1087 | + */ |
| 1088 | +static int |
| 1089 | +batadv_mcast_forw_want_all_ipv4(struct batadv_priv *bat_priv, |
| 1090 | + struct sk_buff *skb, unsigned short vid) |
| 1091 | +{ |
| 1092 | + struct batadv_orig_node *orig_node; |
| 1093 | + int ret = NET_XMIT_SUCCESS; |
| 1094 | + struct sk_buff *newskb; |
| 1095 | + |
| 1096 | + rcu_read_lock(); |
| 1097 | + hlist_for_each_entry_rcu(orig_node, |
| 1098 | + &bat_priv->mcast.want_all_ipv4_list, |
| 1099 | + mcast_want_all_ipv4_node) { |
| 1100 | + newskb = skb_copy(skb, GFP_ATOMIC); |
| 1101 | + if (!newskb) { |
| 1102 | + ret = NET_XMIT_DROP; |
| 1103 | + break; |
| 1104 | + } |
| 1105 | + |
| 1106 | + batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0, |
| 1107 | + orig_node, vid); |
| 1108 | + } |
| 1109 | + rcu_read_unlock(); |
| 1110 | + return ret; |
| 1111 | +} |
| 1112 | + |
| 1113 | +/** |
| 1114 | + * batadv_mcast_forw_want_all_ipv6() - forward to nodes with want-all-ipv6 |
| 1115 | + * @bat_priv: the bat priv with all the soft interface information |
| 1116 | + * @skb: The multicast packet to transmit |
| 1117 | + * @vid: the vlan identifier |
| 1118 | + * |
| 1119 | + * Sends copies of a frame with multicast destination to any node with a |
| 1120 | + * BATADV_MCAST_WANT_ALL_IPV6 flag set. A transmission is performed via a |
| 1121 | + * batman-adv unicast packet for each such destination node. |
| 1122 | + * |
| 1123 | + * Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS |
| 1124 | + * otherwise. |
| 1125 | + */ |
| 1126 | +static int |
| 1127 | +batadv_mcast_forw_want_all_ipv6(struct batadv_priv *bat_priv, |
| 1128 | + struct sk_buff *skb, unsigned short vid) |
| 1129 | +{ |
| 1130 | + struct batadv_orig_node *orig_node; |
| 1131 | + int ret = NET_XMIT_SUCCESS; |
| 1132 | + struct sk_buff *newskb; |
| 1133 | + |
| 1134 | + rcu_read_lock(); |
| 1135 | + hlist_for_each_entry_rcu(orig_node, |
| 1136 | + &bat_priv->mcast.want_all_ipv6_list, |
| 1137 | + mcast_want_all_ipv6_node) { |
| 1138 | + newskb = skb_copy(skb, GFP_ATOMIC); |
| 1139 | + if (!newskb) { |
| 1140 | + ret = NET_XMIT_DROP; |
| 1141 | + break; |
| 1142 | + } |
| 1143 | + |
| 1144 | + batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0, |
| 1145 | + orig_node, vid); |
1017 | 1146 | }
|
| 1147 | + rcu_read_unlock(); |
| 1148 | + return ret; |
| 1149 | +} |
| 1150 | + |
| 1151 | +/** |
| 1152 | + * batadv_mcast_forw_want_all() - forward packet to nodes in a want-all list |
| 1153 | + * @bat_priv: the bat priv with all the soft interface information |
| 1154 | + * @skb: the multicast packet to transmit |
| 1155 | + * @vid: the vlan identifier |
| 1156 | + * |
| 1157 | + * Sends copies of a frame with multicast destination to any node with a |
| 1158 | + * BATADV_MCAST_WANT_ALL_IPV4 or BATADV_MCAST_WANT_ALL_IPV6 flag set. A |
| 1159 | + * transmission is performed via a batman-adv unicast packet for each such |
| 1160 | + * destination node. |
| 1161 | + * |
| 1162 | + * Return: NET_XMIT_DROP on memory allocation failure or if the protocol family |
| 1163 | + * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise. |
| 1164 | + */ |
| 1165 | +static int |
| 1166 | +batadv_mcast_forw_want_all(struct batadv_priv *bat_priv, |
| 1167 | + struct sk_buff *skb, unsigned short vid) |
| 1168 | +{ |
| 1169 | + switch (ntohs(eth_hdr(skb)->h_proto)) { |
| 1170 | + case ETH_P_IP: |
| 1171 | + return batadv_mcast_forw_want_all_ipv4(bat_priv, skb, vid); |
| 1172 | + case ETH_P_IPV6: |
| 1173 | + return batadv_mcast_forw_want_all_ipv6(bat_priv, skb, vid); |
| 1174 | + default: |
| 1175 | + /* we shouldn't be here... */ |
| 1176 | + return NET_XMIT_DROP; |
| 1177 | + } |
| 1178 | +} |
| 1179 | + |
| 1180 | +/** |
| 1181 | + * batadv_mcast_forw_send() - send packet to any detected multicast recpient |
| 1182 | + * @bat_priv: the bat priv with all the soft interface information |
| 1183 | + * @skb: the multicast packet to transmit |
| 1184 | + * @vid: the vlan identifier |
| 1185 | + * |
| 1186 | + * Sends copies of a frame with multicast destination to any node that signaled |
| 1187 | + * interest in it, that is either via the translation table or the according |
| 1188 | + * want-all flags. A transmission is performed via a batman-adv unicast packet |
| 1189 | + * for each such destination node. |
| 1190 | + * |
| 1191 | + * The given skb is consumed/freed. |
| 1192 | + * |
| 1193 | + * Return: NET_XMIT_DROP on memory allocation failure or if the protocol family |
| 1194 | + * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise. |
| 1195 | + */ |
| 1196 | +int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb, |
| 1197 | + unsigned short vid) |
| 1198 | +{ |
| 1199 | + int ret; |
| 1200 | + |
| 1201 | + ret = batadv_mcast_forw_tt(bat_priv, skb, vid); |
| 1202 | + if (ret != NET_XMIT_SUCCESS) { |
| 1203 | + kfree_skb(skb); |
| 1204 | + return ret; |
| 1205 | + } |
| 1206 | + |
| 1207 | + ret = batadv_mcast_forw_want_all(bat_priv, skb, vid); |
| 1208 | + if (ret != NET_XMIT_SUCCESS) { |
| 1209 | + kfree_skb(skb); |
| 1210 | + return ret; |
| 1211 | + } |
| 1212 | + |
| 1213 | + consume_skb(skb); |
| 1214 | + return ret; |
1018 | 1215 | }
|
1019 | 1216 |
|
1020 | 1217 | /**
|
|
0 commit comments