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 }
static int sipc4_add_hdlc(struct sipc4_tx_data *data, void *header, int header_size, bool head, bool tail) { struct sk_buff *skb_new; int headroom = 0; int tailroom = 0; if (!head && !tail) return 0; if (head) headroom = sizeof(hdlc_start) + header_size; if (tail) tailroom = sizeof(hdlc_end); skb_new = skb_copy_expand(data->skb, headroom, tailroom, GFP_ATOMIC); if (!skb_new) return -ENOMEM; dev_kfree_skb_any(data->skb); if (head) { memcpy(skb_push(skb_new, header_size), header, header_size); memcpy(skb_push(skb_new, sizeof(hdlc_start)), hdlc_start, sizeof(hdlc_start)); } if (tail) memcpy(skb_put(skb_new, sizeof(hdlc_end)), hdlc_end, sizeof(hdlc_end)); data->skb = skb_new; return 0; }
/* * 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; }
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; }
static struct sk_buff *rmnet_usb_data_mux(struct sk_buff *skb, unsigned int id) { struct mux_hdr *hdr; size_t len; struct sk_buff *new_skb; if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) { new_skb = skb_copy_expand(skb, skb_headroom(skb), 4 - (skb->len & 0x3), GFP_ATOMIC); dev_kfree_skb_any(skb); if (new_skb == NULL) { pr_err("%s: cannot allocate skb\n", __func__); return NULL; } skb = new_skb; } hdr = (struct mux_hdr *)skb_push(skb, sizeof(struct mux_hdr)); hdr->mux_id = id + 1; len = skb->len - sizeof(struct mux_hdr); skb_put(skb, ALIGN(len, 4) - len); hdr->pkt_len_w_padding = cpu_to_le16(skb->len - sizeof(struct mux_hdr)); hdr->padding_info = (ALIGN(len, 4) - len) << MUX_PAD_SHIFT; return skb; }
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; }
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 packet and our header is smaler than 64 pad to 64 (+ ZLP) */ if ((pack_with_header_len) < dev->maxpacket) need_tail = dev->maxpacket - pack_with_header_len + 1; /* * usbnet would send a ZLP if packetlength mod urbsize == 0 for us, * but we need to know ourself, because this would add to the length * we send down to the device... */ 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; }
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; }
/* 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; }
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; }
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; }
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; }
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; }
/* 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; }
static int vnet_xmit(struct sk_buff *skb, struct net_device *ndev) { int ret; struct raw_hdr hd; struct sk_buff *skb_new; struct vnet *vnet = netdev_priv(ndev); struct io_device *iod = vnet->iod; /* umts doesn't need to discard ethernet header */ if (iod->net_typ != UMTS_NETWORK) { if (iod->id >= PSD_DATA_CHID_BEGIN && iod->id <= PSD_DATA_CHID_END) skb_pull(skb, sizeof(struct ethhdr)); } hd.len = skb->len + sizeof(hd); hd.control = 0; hd.channel = iod->id & 0x1F; skb_new = skb_copy_expand(skb, sizeof(hd) + sizeof(hdlc_start), sizeof(hdlc_end), GFP_ATOMIC); if (!skb_new) { dev_kfree_skb_any(skb); return -ENOMEM; } memcpy(skb_push(skb_new, sizeof(hd)), &hd, sizeof(hd)); memcpy(skb_push(skb_new, sizeof(hdlc_start)), hdlc_start, sizeof(hdlc_start)); memcpy(skb_put(skb_new, sizeof(hdlc_end)), hdlc_end, sizeof(hdlc_end)); ret = iod->link->send(iod->link, iod, skb_new); if (ret < 0) { netif_stop_queue(ndev); dev_kfree_skb_any(skb); return NETDEV_TX_BUSY; } ndev->stats.tx_packets++; ndev->stats.tx_bytes += skb->len; dev_kfree_skb_any(skb); return NETDEV_TX_OK; }
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); if (unlikely((sizeof *hdr) <= room)) goto fill; 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; } } skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags); dev_kfree_skb_any(skb); if (unlikely(!skb2)) return skb2; skb = skb2; 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 = cpu_to_le32(sizeof(*hdr) - 8); hdr->data_len = cpu_to_le32(len); return skb; }
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; }
/* * 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; }
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); }
/** 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; }
static void roq_eth_pass_skb_up(struct roq_eth_priv *vdev, struct sk_buff *skb, int size) { struct sk_buff *skb_shrinked; int err; skb_put(skb, size); skb->dev = vdev->ndev; skb->protocol = eth_type_trans(skb, vdev->ndev); skb->ip_summed = CHECKSUM_UNNECESSARY; vdev->stats.rx_packets++; vdev->stats.rx_bytes += skb->len; if (size < ETH_DATA_LEN) { /* * this call shrinks data buffer to real data length, * otherwise ping doesn't work */ skb_shrinked = skb_copy_expand(skb, skb_headroom(skb), 0, GFP_ATOMIC); dev_kfree_skb(skb); } else skb_shrinked = skb; //printk("%s:%d\n", __func__, __LINE__); if (likely(skb_shrinked)) { err = netif_receive_skb(skb_shrinked); if (unlikely(err)) { if (err == NET_RX_DROP) pr_warn("netif_receive_skb: dropped: %d : %d\n", skb->len, size); else pr_warn("netif_receive_skb: %d\n", err); } } else { pr_warn("skb_copy_expand: dropped\n"); } return; }
int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev) { int notify_stop = FALSE; struct usbdrv_private *macp = dev->ml_priv; #if 0 /* Test code */ { struct sk_buff* s; s = skb_copy_expand(skb, 8, 0, GFP_ATOMIC); skb_push(s, 8); s->data[0] = 'z'; s->data[1] = 'y'; s->data[2] = 'd'; s->data[3] = 'a'; s->data[4] = 's'; printk("len1=%d, len2=%d", skb->len, s->len); netlink_broadcast(rtnl, s, 0, RTMGRP_LINK, GFP_ATOMIC); } #endif #if ZM_DISABLE_XMIT dev_kfree_skb_irq(skb); #else zfiTxSendEth(dev, skb, 0); #endif macp->drv_stats.net_stats.tx_bytes += skb->len; macp->drv_stats.net_stats.tx_packets++; //dev_kfree_skb_irq(skb); if (notify_stop) { netif_carrier_off(dev); netif_stop_queue(dev); } return NETDEV_TX_OK; }
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); }
static int rmnet_mhi_process_fragment(struct rmnet_mhi_private *rmnet_mhi_ptr, struct sk_buff *skb, int frag) { struct sk_buff *temp_skb; if (rmnet_mhi_ptr->frag_skb) { /* Merge the new skb into the old fragment */ temp_skb = skb_copy_expand(rmnet_mhi_ptr->frag_skb, MHI_RX_HEADROOM, skb->len, GFP_ATOMIC); if (!temp_skb) { kfree(rmnet_mhi_ptr->frag_skb); rmnet_mhi_ptr->frag_skb = NULL; return -ENOMEM; } kfree_skb(rmnet_mhi_ptr->frag_skb); rmnet_mhi_ptr->frag_skb = temp_skb; memcpy(skb_put(rmnet_mhi_ptr->frag_skb, skb->len), skb->data, skb->len); kfree_skb(skb); if (!frag) { /* Last fragmented piece was received, ship it */ netif_receive_skb(rmnet_mhi_ptr->frag_skb); rmnet_mhi_ptr->frag_skb = NULL; } } else { if (frag) { /* This is the first fragment */ rmnet_mhi_ptr->frag_skb = skb; rx_fragmentation[rmnet_mhi_ptr->dev_index]++; } else { netif_receive_skb(skb); } } return 0; }
int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) { int copyflag; int elt; struct sk_buff *skb1, **skb_p; /* If skb is cloned or its head is paged, reallocate * head pulling out all the pages (pages are considered not writable * at the moment even if they are anonymous). */ if ((skb_cloned(skb) || skb_shinfo(skb)->nr_frags) && __pskb_pull_tail(skb, skb_pagelen(skb)-skb_headlen(skb)) == NULL) return -ENOMEM; /* Easy case. Most of packets will go this way. */ if (!skb_shinfo(skb)->frag_list) { /* A little of trouble, not enough of space for trailer. * This should not happen, when stack is tuned to generate * good frames. OK, on miss we reallocate and reserve even more * space, 128 bytes is fair. */ if (skb_tailroom(skb) < tailbits && pskb_expand_head(skb, 0, tailbits-skb_tailroom(skb)+128, GFP_ATOMIC)) return -ENOMEM; /* Voila! */ *trailer = skb; return 1; } /* Misery. We are in troubles, going to mincer fragments... */ elt = 1; skb_p = &skb_shinfo(skb)->frag_list; copyflag = 0; while ((skb1 = *skb_p) != NULL) { int ntail = 0; /* The fragment is partially pulled by someone, * this can happen on input. Copy it and everything * after it. */ if (skb_shared(skb1)) copyflag = 1; /* If the skb is the last, worry about trailer. */ if (skb1->next == NULL && tailbits) { if (skb_shinfo(skb1)->nr_frags || skb_shinfo(skb1)->frag_list || skb_tailroom(skb1) < tailbits) ntail = tailbits + 128; } if (copyflag || skb_cloned(skb1) || ntail || skb_shinfo(skb1)->nr_frags || skb_shinfo(skb1)->frag_list) { struct sk_buff *skb2; /* F**k, we are miserable poor guys... */ if (ntail == 0) skb2 = skb_copy(skb1, GFP_ATOMIC); else skb2 = skb_copy_expand(skb1, skb_headroom(skb1), ntail, GFP_ATOMIC); if (unlikely(skb2 == NULL)) return -ENOMEM; if (skb1->sk) skb_set_owner_w(skb2, skb1->sk); /* Looking around. Are we still alive? * OK, link new skb, drop old one */ skb2->next = skb1->next; *skb_p = skb2; kfree_skb(skb1); skb1 = skb2; } elt++; *trailer = skb1; skb_p = &skb1->next; } return elt; }
int msm_rmnet_sdio_write(uint32_t id, struct sk_buff *skb) { int rc = 0; struct sdio_mux_hdr *hdr; unsigned long flags; struct sk_buff *new_skb; if (!skb) { pr_err("[lte] Error - %s\n", __func__); return -EINVAL; } DBG("[lte] %s: writing to ch %d len %d\n", __func__, id, skb->len); spin_lock_irqsave(&sdio_ch[id].lock, flags); if (!sdio_ch_is_local_open(id)) { pr_err("[lte] Error - %s: port not open: %d\n", __func__, sdio_ch[id].status); rc = -ENODEV; goto write_done; } if (sdio_ch[id].skb) { pr_err("[lte] Error - %s: packet pending ch: %d\n", __func__, id); rc = -EPERM; goto write_done; } /* if skb do not have any tailroom for padding, copy the skb into a new expanded skb */ if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) { /* revisit, probably dev_alloc_skb and memcpy is effecient */ new_skb = skb_copy_expand(skb, skb_headroom(skb), 4 - (skb->len & 0x3), GFP_KERNEL); if (new_skb == NULL) { pr_err("[lte] Error - %s: cannot allocate skb\n", __func__); rc = -ENOMEM; goto write_done; } dev_kfree_skb_any(skb); skb = new_skb; DBG_INC_WRITE_CPY(skb->len); } hdr = (struct sdio_mux_hdr *)skb_push(skb, sizeof(struct sdio_mux_hdr)); /* caller should allocate for hdr and padding hdr is fine, padding is tricky */ hdr->magic_num = SDIO_MUX_HDR_MAGIC_NO; hdr->cmd = SDIO_MUX_HDR_CMD_DATA; hdr->reserved = 0; hdr->ch_id = id; hdr->pkt_len = skb->len - sizeof(struct sdio_mux_hdr); if (skb->len & 0x3) skb_put(skb, 4 - (skb->len & 0x3)); hdr->pad_len = skb->len - (sizeof(struct sdio_mux_hdr) + hdr->pkt_len); DBG("[lte] %s: [RIL][write][index %d] data %p, tail %p skb len %d pkt len %d pad len %d\n", __func__, hdr->ch_id, skb->data, skb->tail, skb->len, hdr->pkt_len, hdr->pad_len); sdio_ch[id].skb = skb; queue_work(sdio_mux_workqueue, &work_sdio_mux_write); write_done: spin_unlock_irqrestore(&sdio_ch[id].lock, flags); return rc; }
struct sk_buff * ip6_reconstruct_copy_pkt(struct sk_buff *skb) { struct sk_buff *new_skb, *temp_skb; struct ipv6hdr * ip6_hdr = ipv6_hdr(skb); struct ip6_dst_hdr *ip6_dst; struct timeval tv;//get time int extend_len = sizeof(struct ip6_dst_hdr); ip6_hdr->nexthdr = 0x3c;//set next header as 60 which means next destination header. ip6_hdr->payload_len = htons(ntohs(ip6_hdr->payload_len) + extend_len); //copy from the *skb to new_skb new_skb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + extend_len, GFP_ATOMIC); if(new_skb == NULL) { PRINT("Allocate new sk_buffer error!\n"); //FIXME:if error happens ,will free the last struct cause any problem? //kfree_skb(skb); return NULL; } //set the new_skb if(skb->sk != NULL) skb_set_owner_w(new_skb, skb->sk); //move tail to tail + sizeof(ip6_dst_hdr) skb_put(new_skb,extend_len); //insert a ip6_dst_hdr between the memory memcpy (new_skb->data, skb->data, 40);//assume that the ip header has 40 bytes memcpy (new_skb->data + 40 + sizeof (struct ip6_dst_hdr), skb->data + 40, skb->len - 40); //release the old struct //call kfree_skb will crash the system, so here use a compromise way to drop the old skb in //kfree_skb(skb); skb = new_skb;//skb pointer to new_skb //turn the space to ip6_dst struct ip6_dst = (struct ip6_dst_hdr *)(skb->data + 40); memset(ip6_dst,0,extend_len);//clear //add ipv6 destination header ip6_dst->ip6d_nxt = 0x11; ip6_dst->ip6d_len = 0x01; ip6_dst->ip6d_opt_type = 0x15;// type of option ip6_dst->ip6d_opt_len = 0x0c; do_gettimeofday(&tv); //ip6_dst->ip6d_sec =x(2.4.21-37.EL htonl(tv.tv_sec); ip6_dst->ip6d_sec = htonl(tv.tv_sec); ip6_dst->ip6d_usec = htonl(tv.tv_usec); sample_seq++; if(sample_seq==0xffffffff)//if overflow ,reset { sample_seq=0; } ip6_dst->ip6d_ssn = htonl(sample_seq); return skb; }
/* Create and initialize an SCTP_ASSOC_CHANGE event. * * 5.3.1.1 SCTP_ASSOC_CHANGE * * Communication notifications inform the ULP that an SCTP association * has either begun or ended. The identifier for a new association is * provided by this notification. * * Note: There is no field checking here. If a field is unused it will be * zero'd out. */ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( const struct sctp_association *asoc, __u16 flags, __u16 state, __u16 error, __u16 outbound, __u16 inbound, struct sctp_chunk *chunk, gfp_t gfp) { struct sctp_ulpevent *event; struct sctp_assoc_change *sac; struct sk_buff *skb; /* If the lower layer passed in the chunk, it will be * an ABORT, so we need to include it in the sac_info. */ if (chunk) { /* Copy the chunk data to a new skb and reserve enough * head room to use as notification. */ skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_assoc_change), 0, gfp); if (!skb) goto fail; /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); /* Include the notification structure */ sac = (struct sctp_assoc_change *) skb_push(skb, sizeof(struct sctp_assoc_change)); /* Trim the buffer to the right length. */ skb_trim(skb, sizeof(struct sctp_assoc_change) + ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); } else { event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), MSG_NOTIFICATION, gfp); if (!event) goto fail; skb = sctp_event2skb(event); sac = (struct sctp_assoc_change *) skb_put(skb, sizeof(struct sctp_assoc_change)); } /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE * * sac_type: * It should be SCTP_ASSOC_CHANGE. */ sac->sac_type = SCTP_ASSOC_CHANGE; /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE * * sac_state: 32 bits (signed integer) * This field holds one of a number of values that communicate the * event that happened to the association. */ sac->sac_state = state; /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE * * sac_flags: 16 bits (unsigned integer) * Currently unused. */ sac->sac_flags = 0; /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE * * sac_length: sizeof (__u32) * This field is the total length of the notification data, including * the notification header. */ sac->sac_length = skb->len; /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE * * sac_error: 32 bits (signed integer) * * If the state was reached due to a error condition (e.g. * COMMUNICATION_LOST) any relevant error information is available in * this field. This corresponds to the protocol error codes defined in * [SCTP]. */ sac->sac_error = error; /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE * * sac_outbound_streams: 16 bits (unsigned integer) * sac_inbound_streams: 16 bits (unsigned integer) * * The maximum number of streams allowed in each direction are * available in sac_outbound_streams and sac_inbound streams. */ sac->sac_outbound_streams = outbound; sac->sac_inbound_streams = inbound; /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE * * sac_assoc_id: sizeof (sctp_assoc_t) * * The association id field, holds the identifier for the association. * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ sctp_ulpevent_set_owner(event, asoc); sac->sac_assoc_id = sctp_assoc2id(asoc); return event; fail: return NULL; }
/* Create and initialize a SCTP_SEND_FAILED notification. * * Socket Extensions for SCTP - draft-01 * 5.3.1.4 SCTP_SEND_FAILED */ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( const struct sctp_association *asoc, struct sctp_chunk *chunk, __u16 flags, __u32 error, gfp_t gfp) { struct sctp_ulpevent *event; struct sctp_send_failed *ssf; struct sk_buff *skb; /* Pull off any padding. */ int len = ntohs(chunk->chunk_hdr->length); /* Make skb with more room so we can prepend notification. */ skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_send_failed), /* headroom */ 0, /* tailroom */ gfp); if (!skb) goto fail; /* Pull off the common chunk header and DATA header. */ skb_pull(skb, sizeof(struct sctp_data_chunk)); len -= sizeof(struct sctp_data_chunk); /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); ssf = (struct sctp_send_failed *) skb_push(skb, sizeof(struct sctp_send_failed)); /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_type: * It should be SCTP_SEND_FAILED. */ ssf->ssf_type = SCTP_SEND_FAILED; /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_flags: 16 bits (unsigned integer) * The flag value will take one of the following values * * SCTP_DATA_UNSENT - Indicates that the data was never put on * the wire. * * SCTP_DATA_SENT - Indicates that the data was put on the wire. * Note that this does not necessarily mean that the * data was (or was not) successfully delivered. */ ssf->ssf_flags = flags; /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_length: sizeof (__u32) * This field is the total length of the notification data, including * the notification header. */ ssf->ssf_length = sizeof(struct sctp_send_failed) + len; skb_trim(skb, ssf->ssf_length); /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_error: 16 bits (unsigned integer) * This value represents the reason why the send failed, and if set, * will be a SCTP protocol error code as defined in [SCTP] section * 3.3.10. */ ssf->ssf_error = error; /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_info: sizeof (struct sctp_sndrcvinfo) * The original send information associated with the undelivered * message. */ memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); /* Per TSVWG discussion with Randy. Allow the application to * ressemble a fragmented message. */ ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags; /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_assoc_id: sizeof (sctp_assoc_t) * The association id field, sf_assoc_id, holds the identifier for the * association. All notifications for a given association have the * same association identifier. For TCP style socket, this field is * ignored. */ sctp_ulpevent_set_owner(event, asoc); ssf->ssf_assoc_id = sctp_assoc2id(asoc); return event; fail: return NULL; }
/* 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 = WORD_ROUND(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(struct sctp_remote_error), 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(struct sctp_remote_error)); /* Trim the buffer to the right length. */ skb_trim(skb, sizeof(struct sctp_remote_error) + elen); /* Socket Extensions for SCTP * 5.3.1.3 SCTP_REMOTE_ERROR * * sre_type: * It should be SCTP_REMOTE_ERROR. */ sre->sre_type = SCTP_REMOTE_ERROR; /* * Socket Extensions for SCTP * 5.3.1.3 SCTP_REMOTE_ERROR * * sre_flags: 16 bits (unsigned integer) * Currently unused. */ sre->sre_flags = 0; /* Socket Extensions for SCTP * 5.3.1.3 SCTP_REMOTE_ERROR * * sre_length: sizeof (__u32) * * This field is the total length of the notification data, * including the notification header. */ sre->sre_length = skb->len; /* Socket Extensions for SCTP * 5.3.1.3 SCTP_REMOTE_ERROR * * sre_error: 16 bits (unsigned integer) * This value represents one of the Operational Error causes defined in * the SCTP specification, in network byte order. */ sre->sre_error = cause; /* Socket Extensions for SCTP * 5.3.1.3 SCTP_REMOTE_ERROR * * sre_assoc_id: sizeof (sctp_assoc_t) * * The association id field, holds the identifier for the association. * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ sctp_ulpevent_set_owner(event, asoc); sre->sre_assoc_id = sctp_assoc2id(asoc); return event; fail: return NULL; }