| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Generic HDLC support routines for Linux |
|---|
| 3 | 4 | * Frame Relay support |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 8 | | - * under the terms of version 2 of the GNU General Public License |
|---|
| 9 | | - * as published by the Free Software Foundation. |
|---|
| 10 | 7 | * |
|---|
| 11 | 8 | |
|---|
| 12 | 9 | Theory of PVC state |
|---|
| .. | .. |
|---|
| 274 | 271 | } |
|---|
| 275 | 272 | |
|---|
| 276 | 273 | |
|---|
| 277 | | -static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) |
|---|
| 274 | +static int fr_hard_header(struct sk_buff *skb, u16 dlci) |
|---|
| 278 | 275 | { |
|---|
| 279 | | - struct sk_buff *skb = *skb_p; |
|---|
| 280 | | - |
|---|
| 281 | 276 | if (!skb->dev) { /* Control packets */ |
|---|
| 282 | 277 | switch (dlci) { |
|---|
| 283 | 278 | case LMI_CCITT_ANSI_DLCI: |
|---|
| .. | .. |
|---|
| 319 | 314 | } |
|---|
| 320 | 315 | |
|---|
| 321 | 316 | } else if (skb->dev->type == ARPHRD_ETHER) { |
|---|
| 322 | | - if (skb_headroom(skb) < 10) { |
|---|
| 323 | | - struct sk_buff *skb2 = skb_realloc_headroom(skb, 10); |
|---|
| 324 | | - if (!skb2) |
|---|
| 325 | | - return -ENOBUFS; |
|---|
| 326 | | - dev_kfree_skb(skb); |
|---|
| 327 | | - skb = *skb_p = skb2; |
|---|
| 328 | | - } |
|---|
| 329 | 317 | skb_push(skb, 10); |
|---|
| 330 | 318 | skb->data[3] = FR_PAD; |
|---|
| 331 | 319 | skb->data[4] = NLPID_SNAP; |
|---|
| .. | .. |
|---|
| 419 | 407 | { |
|---|
| 420 | 408 | struct pvc_device *pvc = dev->ml_priv; |
|---|
| 421 | 409 | |
|---|
| 422 | | - if (pvc->state.active) { |
|---|
| 423 | | - if (dev->type == ARPHRD_ETHER) { |
|---|
| 424 | | - int pad = ETH_ZLEN - skb->len; |
|---|
| 425 | | - if (pad > 0) { /* Pad the frame with zeros */ |
|---|
| 426 | | - int len = skb->len; |
|---|
| 427 | | - if (skb_tailroom(skb) < pad) |
|---|
| 428 | | - if (pskb_expand_head(skb, 0, pad, |
|---|
| 429 | | - GFP_ATOMIC)) { |
|---|
| 430 | | - dev->stats.tx_dropped++; |
|---|
| 431 | | - dev_kfree_skb(skb); |
|---|
| 432 | | - return NETDEV_TX_OK; |
|---|
| 433 | | - } |
|---|
| 434 | | - skb_put(skb, pad); |
|---|
| 435 | | - memset(skb->data + len, 0, pad); |
|---|
| 436 | | - } |
|---|
| 437 | | - } |
|---|
| 438 | | - skb->dev = dev; |
|---|
| 439 | | - if (!fr_hard_header(&skb, pvc->dlci)) { |
|---|
| 440 | | - dev->stats.tx_bytes += skb->len; |
|---|
| 441 | | - dev->stats.tx_packets++; |
|---|
| 442 | | - if (pvc->state.fecn) /* TX Congestion counter */ |
|---|
| 443 | | - dev->stats.tx_compressed++; |
|---|
| 444 | | - skb->dev = pvc->frad; |
|---|
| 445 | | - skb->protocol = htons(ETH_P_HDLC); |
|---|
| 446 | | - skb_reset_network_header(skb); |
|---|
| 447 | | - dev_queue_xmit(skb); |
|---|
| 448 | | - return NETDEV_TX_OK; |
|---|
| 410 | + if (!pvc->state.active) |
|---|
| 411 | + goto drop; |
|---|
| 412 | + |
|---|
| 413 | + if (dev->type == ARPHRD_ETHER) { |
|---|
| 414 | + int pad = ETH_ZLEN - skb->len; |
|---|
| 415 | + |
|---|
| 416 | + if (pad > 0) { /* Pad the frame with zeros */ |
|---|
| 417 | + if (__skb_pad(skb, pad, false)) |
|---|
| 418 | + goto drop; |
|---|
| 419 | + skb_put(skb, pad); |
|---|
| 449 | 420 | } |
|---|
| 450 | 421 | } |
|---|
| 451 | 422 | |
|---|
| 423 | + /* We already requested the header space with dev->needed_headroom. |
|---|
| 424 | + * So this is just a protection in case the upper layer didn't take |
|---|
| 425 | + * dev->needed_headroom into consideration. |
|---|
| 426 | + */ |
|---|
| 427 | + if (skb_headroom(skb) < 10) { |
|---|
| 428 | + struct sk_buff *skb2 = skb_realloc_headroom(skb, 10); |
|---|
| 429 | + |
|---|
| 430 | + if (!skb2) |
|---|
| 431 | + goto drop; |
|---|
| 432 | + dev_kfree_skb(skb); |
|---|
| 433 | + skb = skb2; |
|---|
| 434 | + } |
|---|
| 435 | + |
|---|
| 436 | + skb->dev = dev; |
|---|
| 437 | + if (fr_hard_header(skb, pvc->dlci)) |
|---|
| 438 | + goto drop; |
|---|
| 439 | + |
|---|
| 440 | + dev->stats.tx_bytes += skb->len; |
|---|
| 441 | + dev->stats.tx_packets++; |
|---|
| 442 | + if (pvc->state.fecn) /* TX Congestion counter */ |
|---|
| 443 | + dev->stats.tx_compressed++; |
|---|
| 444 | + skb->dev = pvc->frad; |
|---|
| 445 | + skb->protocol = htons(ETH_P_HDLC); |
|---|
| 446 | + skb_reset_network_header(skb); |
|---|
| 447 | + dev_queue_xmit(skb); |
|---|
| 448 | + return NETDEV_TX_OK; |
|---|
| 449 | + |
|---|
| 450 | +drop: |
|---|
| 452 | 451 | dev->stats.tx_dropped++; |
|---|
| 453 | | - dev_kfree_skb(skb); |
|---|
| 452 | + kfree_skb(skb); |
|---|
| 454 | 453 | return NETDEV_TX_OK; |
|---|
| 455 | 454 | } |
|---|
| 456 | 455 | |
|---|
| .. | .. |
|---|
| 503 | 502 | memset(skb->data, 0, len); |
|---|
| 504 | 503 | skb_reserve(skb, 4); |
|---|
| 505 | 504 | if (lmi == LMI_CISCO) { |
|---|
| 506 | | - fr_hard_header(&skb, LMI_CISCO_DLCI); |
|---|
| 505 | + fr_hard_header(skb, LMI_CISCO_DLCI); |
|---|
| 507 | 506 | } else { |
|---|
| 508 | | - fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI); |
|---|
| 507 | + fr_hard_header(skb, LMI_CCITT_ANSI_DLCI); |
|---|
| 509 | 508 | } |
|---|
| 510 | 509 | data = skb_tail_pointer(skb); |
|---|
| 511 | 510 | data[i++] = LMI_CALLREF; |
|---|