/* net/atm/raw.c - Raw AAL0 and AAL5 transports */ /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include #include #include #include #include #include #include "common.h" #include "protocols.h" #if 0 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) #else #define DPRINTK(format,args...) #endif /* * SKB == NULL indicates that the link is being closed */ 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 } } static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) { DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize); atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); dev_kfree_skb_any(skb); wake_up(&vcc->sleep); } static int atm_send_aal0(struct atm_vcc *vcc,struct sk_buff *skb) { /* * Note that if vpi/vci are _ANY or _UNSPEC the below will * still work */ if (!capable(CAP_NET_ADMIN) && (((u32 *) skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) != ((vcc->vpi << ATM_HDR_VPI_SHIFT) | (vcc->vci << ATM_HDR_VCI_SHIFT))) { kfree_skb(skb); return -EADDRNOTAVAIL; } return vcc->dev->ops->send(vcc,skb); } int atm_init_aal0(struct atm_vcc *vcc) { vcc->push = atm_push_raw; vcc->pop = atm_pop_raw; vcc->push_oam = NULL; vcc->send = atm_send_aal0; return 0; } int atm_init_aal34(struct atm_vcc *vcc) { vcc->push = atm_push_raw; vcc->pop = atm_pop_raw; vcc->push_oam = NULL; vcc->send = vcc->dev->ops->send; return 0; } int atm_init_aal5(struct atm_vcc *vcc) { vcc->push = atm_push_raw; vcc->pop = atm_pop_raw; vcc->push_oam = NULL; vcc->send = vcc->dev->ops->send; return 0; } EXPORT_SYMBOL(atm_init_aal5);