--- zzzz-none-000/linux-2.4.17/net/atm/raw.c 2000-04-14 16:37:20.000000000 +0000 +++ sangam-fb-401/linux-2.4.17/net/atm/raw.c 2005-06-14 11:09:35.000000000 +0000 @@ -27,9 +27,66 @@ void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb) { + struct tpacket_hdr *h; if (skb) { +#ifndef CONFIG_PACKET_MMAP skb_queue_tail(&vcc->recvq,skb); wake_up(&vcc->sleep); +#else + if (vcc->iovec == 0) { + skb_queue_tail(&vcc->recvq,skb); + wake_up(&vcc->sleep); + } else { + unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; + unsigned short off = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; + unsigned snaplen = skb->len; + + spin_lock(&vcc->recvq.lock); + h = vcc->iovec[vcc->head]; + if (h->tp_status) { + spin_unlock(&vcc->recvq.lock); + atomic_inc(&vcc->stats->rx_drop); + goto ring_is_full; + } + vcc->head = vcc->head != vcc->iovmax ? vcc->head+1 : 0; + spin_unlock(&vcc->recvq.lock); + + if (off + snaplen > vcc->frame_size) { + snaplen = vcc->frame_size - off; + if ((int)snaplen < 0) + snaplen = 0; + } + + memcpy((u8*)h + off, skb->data, snaplen); + + h->tp_len = skb->len; + h->tp_snaplen = snaplen; + h->tp_mac = off; + h->tp_net = off; + h->tp_sec = skb->stamp.tv_sec; + h->tp_usec = skb->stamp.tv_usec; + + h->tp_status = status; + mb(); + + { + struct page *p_start, *p_end; + u8 *h_end = (u8 *)h + off + snaplen - 1; + + p_start = virt_to_page(h); + p_end = virt_to_page(h_end); + while (p_start <= p_end) { + flush_dcache_page(p_start); + p_start++; + } + } + wake_up(&vcc->sleep); + +ring_is_full: + atm_return(vcc,skb->truesize); + dev_kfree_skb_any(skb); + } +#endif } }