0001
0002
0003
0004
0005
0006
0007 #include "fragmentation.h"
0008 #include "main.h"
0009
0010 #include <linux/atomic.h>
0011 #include <linux/byteorder/generic.h>
0012 #include <linux/errno.h>
0013 #include <linux/etherdevice.h>
0014 #include <linux/gfp.h>
0015 #include <linux/if_ether.h>
0016 #include <linux/jiffies.h>
0017 #include <linux/lockdep.h>
0018 #include <linux/minmax.h>
0019 #include <linux/netdevice.h>
0020 #include <linux/skbuff.h>
0021 #include <linux/slab.h>
0022 #include <linux/spinlock.h>
0023 #include <linux/string.h>
0024 #include <uapi/linux/batadv_packet.h>
0025
0026 #include "hard-interface.h"
0027 #include "originator.h"
0028 #include "routing.h"
0029 #include "send.h"
0030
0031
0032
0033
0034
0035
0036
0037
0038 static void batadv_frag_clear_chain(struct hlist_head *head, bool dropped)
0039 {
0040 struct batadv_frag_list_entry *entry;
0041 struct hlist_node *node;
0042
0043 hlist_for_each_entry_safe(entry, node, head, list) {
0044 hlist_del(&entry->list);
0045
0046 if (dropped)
0047 kfree_skb(entry->skb);
0048 else
0049 consume_skb(entry->skb);
0050
0051 kfree(entry);
0052 }
0053 }
0054
0055
0056
0057
0058
0059
0060 void batadv_frag_purge_orig(struct batadv_orig_node *orig_node,
0061 bool (*check_cb)(struct batadv_frag_table_entry *))
0062 {
0063 struct batadv_frag_table_entry *chain;
0064 u8 i;
0065
0066 for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) {
0067 chain = &orig_node->fragments[i];
0068 spin_lock_bh(&chain->lock);
0069
0070 if (!check_cb || check_cb(chain)) {
0071 batadv_frag_clear_chain(&chain->fragment_list, true);
0072 chain->size = 0;
0073 }
0074
0075 spin_unlock_bh(&chain->lock);
0076 }
0077 }
0078
0079
0080
0081
0082
0083
0084 static int batadv_frag_size_limit(void)
0085 {
0086 int limit = BATADV_FRAG_MAX_FRAG_SIZE;
0087
0088 limit -= sizeof(struct batadv_frag_packet);
0089 limit *= BATADV_FRAG_MAX_FRAGMENTS;
0090
0091 return limit;
0092 }
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 static bool batadv_frag_init_chain(struct batadv_frag_table_entry *chain,
0108 u16 seqno)
0109 {
0110 lockdep_assert_held(&chain->lock);
0111
0112 if (chain->seqno == seqno)
0113 return false;
0114
0115 if (!hlist_empty(&chain->fragment_list))
0116 batadv_frag_clear_chain(&chain->fragment_list, true);
0117
0118 chain->size = 0;
0119 chain->seqno = seqno;
0120
0121 return true;
0122 }
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
0138 struct sk_buff *skb,
0139 struct hlist_head *chain_out)
0140 {
0141 struct batadv_frag_table_entry *chain;
0142 struct batadv_frag_list_entry *frag_entry_new = NULL, *frag_entry_curr;
0143 struct batadv_frag_list_entry *frag_entry_last = NULL;
0144 struct batadv_frag_packet *frag_packet;
0145 u8 bucket;
0146 u16 seqno, hdr_size = sizeof(struct batadv_frag_packet);
0147 bool ret = false;
0148
0149
0150
0151
0152
0153 if (skb_linearize(skb) < 0)
0154 goto err;
0155
0156 frag_packet = (struct batadv_frag_packet *)skb->data;
0157 seqno = ntohs(frag_packet->seqno);
0158 bucket = seqno % BATADV_FRAG_BUFFER_COUNT;
0159
0160 frag_entry_new = kmalloc(sizeof(*frag_entry_new), GFP_ATOMIC);
0161 if (!frag_entry_new)
0162 goto err;
0163
0164 frag_entry_new->skb = skb;
0165 frag_entry_new->no = frag_packet->no;
0166
0167
0168
0169
0170
0171 chain = &orig_node->fragments[bucket];
0172 spin_lock_bh(&chain->lock);
0173 if (batadv_frag_init_chain(chain, seqno)) {
0174 hlist_add_head(&frag_entry_new->list, &chain->fragment_list);
0175 chain->size = skb->len - hdr_size;
0176 chain->timestamp = jiffies;
0177 chain->total_size = ntohs(frag_packet->total_size);
0178 ret = true;
0179 goto out;
0180 }
0181
0182
0183 hlist_for_each_entry(frag_entry_curr, &chain->fragment_list, list) {
0184
0185 if (frag_entry_curr->no == frag_entry_new->no)
0186 goto err_unlock;
0187
0188
0189 if (frag_entry_curr->no < frag_entry_new->no) {
0190 hlist_add_before(&frag_entry_new->list,
0191 &frag_entry_curr->list);
0192 chain->size += skb->len - hdr_size;
0193 chain->timestamp = jiffies;
0194 ret = true;
0195 goto out;
0196 }
0197
0198
0199 frag_entry_last = frag_entry_curr;
0200 }
0201
0202
0203 if (likely(frag_entry_last)) {
0204 hlist_add_behind(&frag_entry_new->list, &frag_entry_last->list);
0205 chain->size += skb->len - hdr_size;
0206 chain->timestamp = jiffies;
0207 ret = true;
0208 }
0209
0210 out:
0211 if (chain->size > batadv_frag_size_limit() ||
0212 chain->total_size != ntohs(frag_packet->total_size) ||
0213 chain->total_size > batadv_frag_size_limit()) {
0214
0215
0216
0217
0218 batadv_frag_clear_chain(&chain->fragment_list, true);
0219 chain->size = 0;
0220 } else if (ntohs(frag_packet->total_size) == chain->size) {
0221
0222 hlist_move_list(&chain->fragment_list, chain_out);
0223 chain->size = 0;
0224 }
0225
0226 err_unlock:
0227 spin_unlock_bh(&chain->lock);
0228
0229 err:
0230 if (!ret) {
0231 kfree(frag_entry_new);
0232 kfree_skb(skb);
0233 }
0234
0235 return ret;
0236 }
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247 static struct sk_buff *
0248 batadv_frag_merge_packets(struct hlist_head *chain)
0249 {
0250 struct batadv_frag_packet *packet;
0251 struct batadv_frag_list_entry *entry;
0252 struct sk_buff *skb_out;
0253 int size, hdr_size = sizeof(struct batadv_frag_packet);
0254 bool dropped = false;
0255
0256
0257
0258
0259 entry = hlist_entry(chain->first, struct batadv_frag_list_entry, list);
0260 hlist_del(&entry->list);
0261 skb_out = entry->skb;
0262 kfree(entry);
0263
0264 packet = (struct batadv_frag_packet *)skb_out->data;
0265 size = ntohs(packet->total_size) + hdr_size;
0266
0267
0268 if (pskb_expand_head(skb_out, 0, size - skb_out->len, GFP_ATOMIC) < 0) {
0269 kfree_skb(skb_out);
0270 skb_out = NULL;
0271 dropped = true;
0272 goto free;
0273 }
0274
0275
0276
0277
0278 skb_pull(skb_out, hdr_size);
0279 skb_out->ip_summed = CHECKSUM_NONE;
0280 memmove(skb_out->data - ETH_HLEN, skb_mac_header(skb_out), ETH_HLEN);
0281 skb_set_mac_header(skb_out, -ETH_HLEN);
0282 skb_reset_network_header(skb_out);
0283 skb_reset_transport_header(skb_out);
0284
0285
0286 hlist_for_each_entry(entry, chain, list) {
0287 size = entry->skb->len - hdr_size;
0288 skb_put_data(skb_out, entry->skb->data + hdr_size, size);
0289 }
0290
0291 free:
0292
0293 batadv_frag_clear_chain(chain, dropped);
0294 return skb_out;
0295 }
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311 bool batadv_frag_skb_buffer(struct sk_buff **skb,
0312 struct batadv_orig_node *orig_node_src)
0313 {
0314 struct sk_buff *skb_out = NULL;
0315 struct hlist_head head = HLIST_HEAD_INIT;
0316 bool ret = false;
0317
0318
0319 if (!batadv_frag_insert_packet(orig_node_src, *skb, &head))
0320 goto out_err;
0321
0322
0323 if (hlist_empty(&head))
0324 goto out;
0325
0326 skb_out = batadv_frag_merge_packets(&head);
0327 if (!skb_out)
0328 goto out_err;
0329
0330 out:
0331 ret = true;
0332 out_err:
0333 *skb = skb_out;
0334 return ret;
0335 }
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349 bool batadv_frag_skb_fwd(struct sk_buff *skb,
0350 struct batadv_hard_iface *recv_if,
0351 struct batadv_orig_node *orig_node_src)
0352 {
0353 struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
0354 struct batadv_orig_node *orig_node_dst;
0355 struct batadv_neigh_node *neigh_node = NULL;
0356 struct batadv_frag_packet *packet;
0357 u16 total_size;
0358 bool ret = false;
0359
0360 packet = (struct batadv_frag_packet *)skb->data;
0361 orig_node_dst = batadv_orig_hash_find(bat_priv, packet->dest);
0362 if (!orig_node_dst)
0363 goto out;
0364
0365 neigh_node = batadv_find_router(bat_priv, orig_node_dst, recv_if);
0366 if (!neigh_node)
0367 goto out;
0368
0369
0370
0371
0372 total_size = ntohs(packet->total_size);
0373 if (total_size > neigh_node->if_incoming->net_dev->mtu) {
0374 batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_FWD);
0375 batadv_add_counter(bat_priv, BATADV_CNT_FRAG_FWD_BYTES,
0376 skb->len + ETH_HLEN);
0377
0378 packet->ttl--;
0379 batadv_send_unicast_skb(skb, neigh_node);
0380 ret = true;
0381 }
0382
0383 out:
0384 batadv_orig_node_put(orig_node_dst);
0385 batadv_neigh_node_put(neigh_node);
0386 return ret;
0387 }
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402 static struct sk_buff *batadv_frag_create(struct net_device *net_dev,
0403 struct sk_buff *skb,
0404 struct batadv_frag_packet *frag_head,
0405 unsigned int fragment_size)
0406 {
0407 unsigned int ll_reserved = LL_RESERVED_SPACE(net_dev);
0408 unsigned int tailroom = net_dev->needed_tailroom;
0409 struct sk_buff *skb_fragment;
0410 unsigned int header_size = sizeof(*frag_head);
0411 unsigned int mtu = fragment_size + header_size;
0412
0413 skb_fragment = dev_alloc_skb(ll_reserved + mtu + tailroom);
0414 if (!skb_fragment)
0415 goto err;
0416
0417 skb_fragment->priority = skb->priority;
0418
0419
0420 skb_reserve(skb_fragment, ll_reserved + header_size);
0421 skb_split(skb, skb_fragment, skb->len - fragment_size);
0422
0423
0424 skb_push(skb_fragment, header_size);
0425 memcpy(skb_fragment->data, frag_head, header_size);
0426
0427 err:
0428 return skb_fragment;
0429 }
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439 int batadv_frag_send_packet(struct sk_buff *skb,
0440 struct batadv_orig_node *orig_node,
0441 struct batadv_neigh_node *neigh_node)
0442 {
0443 struct net_device *net_dev = neigh_node->if_incoming->net_dev;
0444 struct batadv_priv *bat_priv;
0445 struct batadv_hard_iface *primary_if = NULL;
0446 struct batadv_frag_packet frag_header;
0447 struct sk_buff *skb_fragment;
0448 unsigned int mtu = net_dev->mtu;
0449 unsigned int header_size = sizeof(frag_header);
0450 unsigned int max_fragment_size, num_fragments;
0451 int ret;
0452
0453
0454
0455
0456 mtu = min_t(unsigned int, mtu, BATADV_FRAG_MAX_FRAG_SIZE);
0457 max_fragment_size = mtu - header_size;
0458
0459 if (skb->len == 0 || max_fragment_size == 0)
0460 return -EINVAL;
0461
0462 num_fragments = (skb->len - 1) / max_fragment_size + 1;
0463 max_fragment_size = (skb->len - 1) / num_fragments + 1;
0464
0465
0466 if (num_fragments > BATADV_FRAG_MAX_FRAGMENTS) {
0467 ret = -EAGAIN;
0468 goto free_skb;
0469 }
0470
0471 bat_priv = orig_node->bat_priv;
0472 primary_if = batadv_primary_if_get_selected(bat_priv);
0473 if (!primary_if) {
0474 ret = -EINVAL;
0475 goto free_skb;
0476 }
0477
0478
0479
0480
0481
0482
0483
0484 if (skb_has_frag_list(skb) && __skb_linearize(skb)) {
0485 ret = -ENOMEM;
0486 goto free_skb;
0487 }
0488
0489
0490 frag_header.packet_type = BATADV_UNICAST_FRAG;
0491 frag_header.version = BATADV_COMPAT_VERSION;
0492 frag_header.ttl = BATADV_TTL;
0493 frag_header.seqno = htons(atomic_inc_return(&bat_priv->frag_seqno));
0494 frag_header.reserved = 0;
0495 frag_header.no = 0;
0496 frag_header.total_size = htons(skb->len);
0497
0498
0499
0500
0501
0502
0503 if (skb->priority >= 256 && skb->priority <= 263)
0504 frag_header.priority = skb->priority - 256;
0505 else
0506 frag_header.priority = 0;
0507
0508 ether_addr_copy(frag_header.orig, primary_if->net_dev->dev_addr);
0509 ether_addr_copy(frag_header.dest, orig_node->orig);
0510
0511
0512 while (skb->len > max_fragment_size) {
0513
0514 if (unlikely(frag_header.no == BATADV_FRAG_MAX_FRAGMENTS - 1)) {
0515 ret = -EINVAL;
0516 goto put_primary_if;
0517 }
0518
0519 skb_fragment = batadv_frag_create(net_dev, skb, &frag_header,
0520 max_fragment_size);
0521 if (!skb_fragment) {
0522 ret = -ENOMEM;
0523 goto put_primary_if;
0524 }
0525
0526 batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
0527 batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
0528 skb_fragment->len + ETH_HLEN);
0529 ret = batadv_send_unicast_skb(skb_fragment, neigh_node);
0530 if (ret != NET_XMIT_SUCCESS) {
0531 ret = NET_XMIT_DROP;
0532 goto put_primary_if;
0533 }
0534
0535 frag_header.no++;
0536 }
0537
0538
0539
0540
0541 ret = skb_cow_head(skb, ETH_HLEN + header_size);
0542 if (ret < 0)
0543 goto put_primary_if;
0544
0545 skb_push(skb, header_size);
0546 memcpy(skb->data, &frag_header, header_size);
0547
0548
0549 batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
0550 batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
0551 skb->len + ETH_HLEN);
0552 ret = batadv_send_unicast_skb(skb, neigh_node);
0553
0554 skb = NULL;
0555
0556 put_primary_if:
0557 batadv_hardif_put(primary_if);
0558 free_skb:
0559 kfree_skb(skb);
0560
0561 return ret;
0562 }