本文整理汇总了C++中skb_copy_expand函数的典型用法代码示例。如果您正苦于以下问题:C++ skb_copy_expand函数的具体用法?C++ skb_copy_expand怎么用?C++ skb_copy_expand使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了skb_copy_expand函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: duplicate_pkt_with_TKIP_MIC
PNDIS_PACKET duplicate_pkt_with_TKIP_MIC(
IN PRTMP_ADAPTER pAd,
IN PNDIS_PACKET pPacket)
{
struct sk_buff *skb, *newskb;
skb = RTPKT_TO_OSPKT(pPacket);
if (skb_tailroom(skb) < TKIP_TX_MIC_SIZE)
{
// alloc a new skb and copy the packet
newskb = skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE, GFP_ATOMIC);
dev_kfree_skb_any(skb);
if (newskb == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("Extend Tx.MIC for packet failed!, dropping packet!\n"));
return NULL;
}
skb = newskb;
}
return OSPKT_TO_RTPKT(skb);
#if 0
if ((data = skb_put(skb, TKIP_TX_MIC_SIZE)) != NULL)
{ // If we can extend it, well, copy it first.
NdisMoveMemory(data, pAd->PrivateInfo.Tx.MIC, TKIP_TX_MIC_SIZE);
}
else
{
// Otherwise, copy the packet.
newskb = skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE, GFP_ATOMIC);
dev_kfree_skb_any(skb);
if (newskb == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("Extend Tx.MIC to packet failed!, dropping packet\n"));
return NULL;
}
skb = newskb;
NdisMoveMemory(skb->tail, pAd->PrivateInfo.Tx.MIC, TKIP_TX_MIC_SIZE);
skb_put(skb, TKIP_TX_MIC_SIZE);
}
return OSPKT_TO_RTPKT(skb);
#endif
}
示例2: ipsec_ocf_ipcomp_copy_expand
/*
* We need to grow the skb to accommodate the expanssion of the ipcomp packet.
*
* The following comment comes from the skb_decompress() which does the
* same...
*
* We have no way of knowing the exact length of the resulting
* decompressed output before we have actually done the decompression.
* For now, we guess that the packet will not be bigger than the
* attached ipsec device's mtu or 16260, whichever is biggest.
* This may be wrong, since the sender's mtu may be bigger yet.
* XXX This must be dealt with later XXX
*/
static int ipsec_ocf_ipcomp_copy_expand(struct ipsec_rcv_state *irs)
{
struct sk_buff *nskb;
unsigned grow_to, grow_by;
ptrdiff_t ptr_delta;
if (!irs->skb)
return IPSEC_RCV_IPCOMPFAILED;
if (irs->skb->dev) {
grow_to = irs->skb->dev->mtu <
16260 ? 16260 : irs->skb->dev->mtu;
} else {
int tot_len;
if (lsw_ip_hdr_version(irs) == 6)
tot_len = ntohs(lsw_ip6_hdr(irs)->payload_len) +
sizeof(struct ipv6hdr);
else
tot_len = ntohs(lsw_ip4_hdr(irs)->tot_len);
grow_to = 65520 - tot_len;
}
grow_by = grow_to - irs->skb->len;
grow_by -= skb_headroom(irs->skb);
grow_by -= skb_tailroom(irs->skb);
/* it's big enough */
if (!grow_by)
return IPSEC_RCV_OK;
nskb = skb_copy_expand(irs->skb, skb_headroom(irs->skb),
skb_tailroom(irs->skb) + grow_by, GFP_ATOMIC);
if (!nskb)
return IPSEC_RCV_ERRMEMALLOC;
memcpy(nskb->head, irs->skb->head, skb_headroom(irs->skb));
skb_set_network_header(nskb,
ipsec_skb_offset(irs->skb,
skb_network_header(irs->skb)));
skb_set_transport_header(nskb,
ipsec_skb_offset(irs->skb,
skb_transport_header(
irs->skb)));
/* update all irs pointers */
ptr_delta = nskb->data - irs->skb->data;
irs->authenticator = (void*)((char*)irs->authenticator + ptr_delta);
irs->iph = (void*)((char*)irs->iph + ptr_delta);
/* flip in the large one */
irs->pre_ipcomp_skb = irs->skb;
irs->skb = nskb;
/* move the tail up to the end to let OCF know how big the buffer is */
if (grow_by > (irs->skb->end - irs->skb->tail))
grow_by = irs->skb->end - irs->skb->tail;
skb_put(irs->skb, grow_by);
return IPSEC_RCV_OK;
}
示例3: ipq_mangle_ipv4
static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
{
int diff;
struct iphdr *user_iph = (struct iphdr *)v->payload;
if (v->data_len < sizeof(*user_iph))
return 0;
diff = v->data_len - e->skb->len;
if (diff < 0)
skb_trim(e->skb, v->data_len);
else if (diff > 0) {
if (v->data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
struct sk_buff *newskb;
newskb = skb_copy_expand(e->skb,
skb_headroom(e->skb),
diff,
GFP_ATOMIC);
if (newskb == NULL) {
printk(KERN_WARNING "ip_queue: OOM "
"in mangle, dropping packet\n");
return -ENOMEM;
}
kfree_skb(e->skb);
e->skb = newskb;
}
skb_put(e->skb, diff);
}
memcpy(e->skb->data, v->payload, v->data_len);
e->skb->nfcache |= NFC_ALTERED;
return 0;
}
示例4: net1080_tx_fixup
static struct sk_buff *
net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
struct sk_buff *skb2;
struct nc_header *header = NULL;
struct nc_trailer *trailer = NULL;
int padlen = sizeof (struct nc_trailer);
int len = skb->len;
if (!((len + padlen + sizeof (struct nc_header)) & 0x01))
padlen++;
if (!skb_cloned(skb)) {
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
if (padlen <= tailroom &&
sizeof(struct nc_header) <= headroom)
/* There's enough head and tail room */
goto encapsulate;
if ((sizeof (struct nc_header) + padlen) <
(headroom + tailroom)) {
/* There's enough total room, so just readjust */
skb->data = memmove(skb->head
+ sizeof (struct nc_header),
skb->data, skb->len);
skb_set_tail_pointer(skb, len);
goto encapsulate;
}
}
/* Create a new skb to use with the correct size */
skb2 = skb_copy_expand(skb,
sizeof (struct nc_header),
padlen,
flags);
dev_kfree_skb_any(skb);
if (!skb2)
return skb2;
skb = skb2;
encapsulate:
/* header first */
header = (struct nc_header *) skb_push(skb, sizeof *header);
header->hdr_len = cpu_to_le16(sizeof (*header));
header->packet_len = cpu_to_le16(len);
header->packet_id = cpu_to_le16((u16)dev->xid++);
/* maybe pad; then trailer */
if (!((skb->len + sizeof *trailer) & 0x01))
*skb_put(skb, 1) = PAD_BYTE;
trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer);
put_unaligned(header->packet_id, &trailer->packet_id);
#if 0
netdev_dbg(dev->net, "frame >tx h %d p %d id %d\n",
header->hdr_len, header->packet_len,
header->packet_id);
#endif
return skb;
}
示例5: skb_headroom
static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev,
struct sk_buff *skb, gfp_t flags)
{
int pack_len = skb->len;
int pack_with_header_len = pack_len + INT51X1_HEADER_SIZE;
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
int need_tail = 0;
__le16 *len;
/* */
if ((pack_with_header_len) < dev->maxpacket)
need_tail = dev->maxpacket - pack_with_header_len + 1;
/*
*/
else if (!(pack_with_header_len % dev->maxpacket))
need_tail = 1;
if (!skb_cloned(skb) &&
(headroom + tailroom >= need_tail + INT51X1_HEADER_SIZE)) {
if (headroom < INT51X1_HEADER_SIZE || tailroom < need_tail) {
skb->data = memmove(skb->head + INT51X1_HEADER_SIZE,
skb->data, skb->len);
skb_set_tail_pointer(skb, skb->len);
}
} else {
struct sk_buff *skb2;
skb2 = skb_copy_expand(skb,
INT51X1_HEADER_SIZE,
need_tail,
flags);
dev_kfree_skb_any(skb);
if (!skb2)
return NULL;
skb = skb2;
}
pack_len += need_tail;
pack_len &= 0x07ff;
len = (__le16 *) __skb_push(skb, INT51X1_HEADER_SIZE);
*len = cpu_to_le16(pack_len);
if(need_tail)
memset(__skb_put(skb, need_tail), 0, need_tail);
return skb;
}
示例6: sctp_ulpevent_make_remote_error
/* Create and initialize an SCTP_REMOTE_ERROR notification.
*
* Note: This assumes that the chunk->skb->data already points to the
* operation error payload.
*
* Socket Extensions for SCTP - draft-01
* 5.3.1.3 SCTP_REMOTE_ERROR
*
* A remote peer may send an Operational Error message to its peer.
* This message indicates a variety of error conditions on an
* association. The entire error TLV as it appears on the wire is
* included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP
* specification [SCTP] and any extensions for a list of possible
* error formats.
*/
struct sctp_ulpevent *
sctp_ulpevent_make_remote_error(const struct sctp_association *asoc,
struct sctp_chunk *chunk, __u16 flags,
gfp_t gfp)
{
struct sctp_ulpevent *event;
struct sctp_remote_error *sre;
struct sk_buff *skb;
sctp_errhdr_t *ch;
__be16 cause;
int elen;
ch = (sctp_errhdr_t *)(chunk->skb->data);
cause = ch->cause;
elen = SCTP_PAD4(ntohs(ch->length)) - sizeof(sctp_errhdr_t);
/* Pull off the ERROR header. */
skb_pull(chunk->skb, sizeof(sctp_errhdr_t));
/* Copy the skb to a new skb with room for us to prepend
* notification with.
*/
skb = skb_copy_expand(chunk->skb, sizeof(*sre), 0, gfp);
/* Pull off the rest of the cause TLV from the chunk. */
skb_pull(chunk->skb, elen);
if (!skb)
goto fail;
/* Embed the event fields inside the cloned skb. */
event = sctp_skb2event(skb);
sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
sre = (struct sctp_remote_error *) skb_push(skb, sizeof(*sre));
/* Trim the buffer to the right length. */
skb_trim(skb, sizeof(*sre) + elen);
/* RFC6458, Section 6.1.3. SCTP_REMOTE_ERROR */
memset(sre, 0, sizeof(*sre));
sre->sre_type = SCTP_REMOTE_ERROR;
sre->sre_flags = 0;
sre->sre_length = skb->len;
sre->sre_error = cause;
sctp_ulpevent_set_owner(event, asoc);
sre->sre_assoc_id = sctp_assoc2id(asoc);
return event;
fail:
return NULL;
}
示例7: ipt_mirror_target
static unsigned int ipt_mirror_target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
const void *targinfo,
void *userinfo)
{
struct rtable *rt;
struct sk_buff *nskb;
unsigned int hh_len;
/* If we are not at FORWARD hook (INPUT/PREROUTING),
* the TTL isn't decreased by the IP stack */
if (hooknum != NF_IP_FORWARD) {
struct iphdr *iph = (*pskb)->nh.iph;
if (iph->ttl <= 1) {
/* this will traverse normal stack, and
* thus call conntrack on the icmp packet */
icmp_send(*pskb, ICMP_TIME_EXCEEDED,
ICMP_EXC_TTL, 0);
return NF_DROP;
}
ip_decrease_ttl(iph);
}
if ((rt = route_mirror(*pskb, hooknum == NF_IP_LOCAL_IN)) == NULL)
return NF_DROP;
hh_len = (rt->u.dst.dev->hard_header_len + 15) & ~15;
/* Copy skb (even if skb is about to be dropped, we can't just
* clone it because there may be other things, such as tcpdump,
* interested in it). We also need to expand headroom in case
* hh_len of incoming interface < hh_len of outgoing interface */
nskb = skb_copy_expand(*pskb, hh_len, skb_tailroom(*pskb), GFP_ATOMIC);
if (nskb == NULL) {
dst_release(&rt->u.dst);
return NF_DROP;
}
dst_release(nskb->dst);
nskb->dst = &rt->u.dst;
ip_rewrite(nskb);
/* Don't let conntrack code see this packet:
it will think we are starting a new
connection! --RR */
ip_direct_send(nskb);
return NF_DROP;
}
示例8: goose_trans_skb
int goose_trans_skb(struct net_device *dev, unsigned char *daddr,
struct sk_buff *__skb, int reliablity)
{
struct sk_buff *skb = __skb;
unsigned int skb_pull_len = NLMSG_LENGTH(0) + sizeof(struct nl_data_header);
if (unlikely((dev == NULL) || (!tran_active)))
goto goose_trans_skb_fail;
/* We use existing skb to form a new one:
*
* skb:
* old skb->data new skb->data
* | |
* -----------------------------------------------------------
* | NLMSG_LENGTH(0) | nl_data_header | goose header | APDU
* -----------------------------------------------------------
* | <== skb_pull_len ==> |
*
*/
skb_pull(skb, skb_pull_len);
skb_reset_network_header(skb);
/* But after pulling, if we have still no enough space for link-layer header,
we have to reconstruct a new skb */
if ((skb->head - skb->network_header) < LL_RESERVED_SPACE(dev)) {
skb = skb_copy_expand(__skb, LL_RESERVED_SPACE(dev), 16, GFP_ATOMIC);
kfree_skb(__skb);
}
/* Specify protocol type and frame information */
skb->dev = dev;
skb->protocol = ETH_P_GOOSE;
skb->pkt_type = PACKET_OUTGOING;
skb->csum = 0;
skb->ip_summed = 0;
/* Set the highest priority */
skb->priority = 0;
if (unlikely(dev_hard_header(skb, dev, ETH_P_GOOSE, daddr, dev->dev_addr, skb->len) < 0))
goto goose_trans_skb_fail;
/* If the message should be transmitted by GOOSE Enhanced Retransmission Mechanism,
call goose_enhan_retrans, otherwise transmit it directly.*/
return reliablity ? goose_enhan_retrans(skb):dev_queue_xmit(skb);
goose_trans_skb_fail:
kfree_skb(skb);
return -1;
}
示例9: ipq_mangle_ipv4
static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
{
int diff;
struct iphdr *user_iph = (struct iphdr *)v->payload;
if (v->data_len < sizeof(*user_iph))
return 0;
diff = v->data_len - e->skb->len;
if (diff < 0)
skb_trim(e->skb, v->data_len);
else if (diff > 0) {
if (v->data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
struct sk_buff *newskb;
newskb = skb_copy_expand(e->skb,
skb_headroom(e->skb),
diff,
GFP_ATOMIC);
if (newskb == NULL) {
printk(KERN_WARNING "ip_queue: OOM "
"in mangle, dropping packet\n");
return -ENOMEM;
}
if (e->skb->sk)
skb_set_owner_w(newskb, e->skb->sk);
kfree_skb(e->skb);
e->skb = newskb;
}
skb_put(e->skb, diff);
}
memcpy(e->skb->data, v->payload, v->data_len);
e->skb->nfcache |= NFC_ALTERED;
/*
* Extra routing may needed on local out, as the QUEUE target never
* returns control to the table.
*/
if (e->info->hook == NF_IP_LOCAL_OUT) {
struct iphdr *iph = e->skb->nh.iph;
if (!(iph->tos == e->rt_info.tos
&& iph->daddr == e->rt_info.daddr
&& iph->saddr == e->rt_info.saddr))
return route_me_harder(e->skb);
}
return 0;
}
示例10: rndis_tx_fixup
static struct sk_buff *
rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
struct rndis_data_hdr *hdr;
struct sk_buff *skb2;
unsigned len = skb->len;
if (likely(!skb_cloned(skb))) {
int room = skb_headroom(skb);
/* enough head room as-is? */
if (unlikely((sizeof *hdr) <= room))
goto fill;
/* enough room, but needs to be readjusted? */
room += skb_tailroom(skb);
if (likely((sizeof *hdr) <= room)) {
skb->data = memmove(skb->head + sizeof *hdr,
skb->data, len);
skb_set_tail_pointer(skb, len);
goto fill;
}
}
/* create a new skb, with the correct size (and tailpad) */
skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags);
dev_kfree_skb_any(skb);
if (unlikely(!skb2))
return skb2;
skb = skb2;
/* fill out the RNDIS header. we won't bother trying to batch
* packets; Linux minimizes wasted bandwidth through tx queues.
*/
fill:
hdr = (void *) __skb_push(skb, sizeof *hdr);
memset(hdr, 0, sizeof *hdr);
hdr->msg_type = RNDIS_MSG_PACKET;
hdr->msg_len = cpu_to_le32(skb->len);
hdr->data_offset = ccpu2(sizeof(*hdr) - 8);
hdr->data_len = cpu_to_le32(len);
/* FIXME make the last packet always be short ... */
return skb;
}
示例11: enlarge_skb
/* Unusual, but possible case. */
static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
{
struct sk_buff *nskb;
if ((*pskb)->len + extra > 65535)
return 0;
nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC);
if (!nskb)
return 0;
/* Transfer socket to new skb. */
if ((*pskb)->sk)
skb_set_owner_w(nskb, (*pskb)->sk);
kfree_skb(*pskb);
*pskb = nskb;
return 1;
}
示例12: genelink_tx_fixup
static struct sk_buff *
genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
int padlen;
int length = skb->len;
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
__le32 *packet_count;
__le32 *packet_len;
// FIXME: magic numbers, bleech
padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
if ((!skb_cloned(skb))
&& ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
skb->data = memmove(skb->head + (4 + 4*1),
skb->data, skb->len);
skb_set_tail_pointer(skb, skb->len);
}
} else {
struct sk_buff *skb2;
skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags);
dev_kfree_skb_any(skb);
skb = skb2;
if (!skb)
return NULL;
}
// attach the packet count to the header
packet_count = (__le32 *) skb_push(skb, (4 + 4*1));
packet_len = packet_count + 1;
*packet_count = cpu_to_le32(1);
*packet_len = cpu_to_le32(length);
// add padding byte
if ((skb->len % dev->maxpacket) == 0)
skb_put(skb, 1);
return skb;
}
示例13: oamkernel_add_pkt_head
/*
* Prototype : oamkernel_add_pkt_head
* Description : recv data from driver
* Input : char main_type
char sub_type
struct sk_buff *skb
void *param
* Return Value : int32
* Calls :
* Called By :
*
* History :
* 1.Date : 2013/6/20
* Author :
* Modification : Created function
*/
int32 oamkernel_add_pkt_head( OS_SK_BUFF_STRU *pst_skb, uint8 type, uint8 PrimID)
{
struct sk_buff *skb = NULL;
int32 l_ret = 0;
if (NULL == pst_skb)
{
OAM_ERROR("para fail\n");
return -EFAIL;
}
l_ret = pst_skb->len;
OAM_INFO("entry:len=%d\n", l_ret);
skb = NULL;
skb = skb_copy_expand(pst_skb, sizeof(struct oam_header),
sizeof(struct oam_end), GFP_ATOMIC);
if (NULL == skb)
{
OAM_ERROR("can't allocate mem for new skb");
return -EINVAL;
}
skb_push(skb,sizeof(struct oam_header));
skb_put(skb,sizeof(struct oam_end));
OAM_INFO("skb->len=%d\n", skb->len);
wifi_tx_add_head(skb->data, type, PrimID, skb->len);
/* push curr skb to skb queue */
skb_queue_tail(&gst_kerenlglobal.rx_wifi_dbg_seq, skb);
if (gst_kerenlglobal.rx_wifi_dbg_seq.qlen > RX_WIFI_QUE_MAX_NUM)
{ /* if rx sdio log queue is too large */
skb = skb_dequeue(&gst_kerenlglobal.rx_wifi_dbg_seq);
kfree_skb(skb);
OAM_ERROR("wifi log queue is too large");
}
hwifi_free_skb(pst_skb);
queue_work(gst_kerenlglobal.oam_rx_workqueue, &gst_kerenlglobal.rx_wifi_work);
return l_ret;
}
示例14: mac80211_hwsim_monitor_rx
static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
struct sk_buff *tx_skb)
{
struct mac80211_hwsim_data *data = hw->priv;
struct sk_buff *skb;
struct hwsim_radiotap_hdr *hdr;
u16 flags;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb);
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
if (!netif_running(hwsim_mon))
return;
skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC);
if (skb == NULL)
return;
hdr = (struct hwsim_radiotap_hdr *) skb_push(skb, sizeof(*hdr));
hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION;
hdr->hdr.it_pad = 0;
hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr));
hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
(1 << IEEE80211_RADIOTAP_RATE) |
(1 << IEEE80211_RADIOTAP_CHANNEL));
hdr->rt_flags = 0;
hdr->rt_rate = txrate->bitrate / 5;
hdr->rt_channel = cpu_to_le16(data->channel->center_freq);
flags = IEEE80211_CHAN_2GHZ;
if (txrate->flags & IEEE80211_RATE_ERP_G)
flags |= IEEE80211_CHAN_OFDM;
else
flags |= IEEE80211_CHAN_CCK;
hdr->rt_chbitmask = cpu_to_le16(flags);
skb->dev = hwsim_mon;
skb_set_mac_header(skb, 0);
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = htons(ETH_P_802_2);
memset(skb->cb, 0, sizeof(skb->cb));
netif_rx(skb);
}
示例15: skb_make_room
/** Make enough room in an skb for extra header and trailer.
*
* @param pskb return parameter for expanded skb
* @param skb skb
* @param head_n required headroom
* @param tail_n required tailroom
* @return 0 on success, error code otherwise
*/
int skb_make_room(struct sk_buff **pskb, struct sk_buff *skb, int head_n, int tail_n){
int err = 0;
int has_headroom = (head_n <= skb_headroom(skb));
int has_tailroom = (tail_n <= skb_tailroom(skb));
int writeable = !skb_cloned(skb) && !skb_shared(skb);
dprintf("> skb=%p headroom=%d head_n=%d tailroom=%d tail_n=%d\n",
skb,
skb_headroom(skb), head_n,
skb_tailroom(skb), tail_n);
if(writeable && has_headroom && has_tailroom){
// There's room! Reuse it.
*pskb = skb;
} else if(writeable && has_tailroom){
// Tailroom, no headroom. Expand header the way GRE does.
struct sk_buff *new_skb = skb_realloc_headroom(skb, head_n + 16);
if(!new_skb){
err = -ENOMEM;
goto exit;
}
kfree_skb(skb);
*pskb = new_skb;
} else {
// No room. Expand. There may be more efficient ways to do
// this, but this is simple and correct.
struct sk_buff *new_skb = skb_copy_expand(skb, head_n + 16, tail_n, GFP_ATOMIC);
if(!new_skb){
err = -ENOMEM;
goto exit;
}
kfree_skb(skb);
*pskb = new_skb;
}
dprintf("> skb=%p headroom=%d head_n=%d tailroom=%d tail_n=%d\n",
*pskb,
skb_headroom(*pskb), head_n,
skb_tailroom(*pskb), tail_n);
exit:
dprintf("< err=%d\n", err);
return err;
}