static int clip_arp_rcv(struct sk_buff *skb) { struct atm_vcc *vcc; DPRINTK("clip_arp_rcv\n"); vcc = ATM_SKB(skb)->vcc; if (!vcc || !atm_charge(vcc,skb->truesize)) { dev_kfree_skb_any(skb); return 0; } DPRINTK("pushing to %p\n",vcc); DPRINTK("using %p\n",CLIP_VCC(vcc)->old_push); CLIP_VCC(vcc)->old_push(vcc,skb); return 0; }
static int clip_assign_device(struct atm_vcc *vcc, int itf) { struct clip_vcc *clip_vcc; knet_netdev_t *dev; if (vcc->push != clip_push) { printk(KERN_WARNING "clip_assign_device: non-CLIP VCC\n"); return -EBADF; } clip_vcc = CLIP_VCC(vcc); for (dev = clip_devs; dev && PRIV(dev)->number != itf; dev = PRIV(dev)->next); if (!dev) { printk(KERN_WARNING "clip_assign_device: no such device\n"); return -ENODEV; } if (clip_vcc->entry) unlink_clip_vcc(clip_vcc); clip_vcc->dev = dev; clip_vcc->global_next = clip_vccs; clip_vccs = clip_vcc; clip_start_resolving(clip_vcc); return 0; }
static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc) { static const char *const class_name[] = { "off", "UBR", "CBR", "VBR", "ABR"}; static const char *const aal_name[] = { "---", "1", "2", "3/4", /* 0- 3 */ "???", "5", "???", "???", /* 4- 7 */ "???", "???", "???", "???", /* 8-11 */ "???", "0", "???", "???"}; /* 12-15 */ seq_printf(seq, "%3d %3d %5d %-3s %7d %-5s %7d %-6s", vcc->dev->number, vcc->vpi, vcc->vci, vcc->qos.aal >= ARRAY_SIZE(aal_name) ? "err" : aal_name[vcc->qos.aal], vcc->qos.rxtp.min_pcr, class_name[vcc->qos.rxtp.traffic_class], vcc->qos.txtp.min_pcr, class_name[vcc->qos.txtp.traffic_class]); if (test_bit(ATM_VF_IS_CLIP, &vcc->flags)) { struct clip_vcc *clip_vcc = CLIP_VCC(vcc); struct net_device *dev; dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL; seq_printf(seq, "CLIP, Itf:%s, Encap:", dev ? dev->name : "none?"); seq_printf(seq, "%s", clip_vcc->encap ? "LLC/SNAP" : "None"); } seq_putc(seq, '\n'); }
static int clip_inarp_send(struct atm_vcc *vcc, u32 remote_ip, u16 op) { struct sk_buff *skb; int allocated_size, error, size = 0; u8 *buff; u32 local_ip; struct atmarphdr *hdr; if (test_bit(ATM_VF_RELEASED, &vcc->flags) || test_bit(ATM_VF_CLOSE, &vcc->flags)) { return vcc->reply; } if (!test_bit(ATM_VF_READY, &vcc->flags)) return -EPIPE; /* align to word boundary */ allocated_size = (MAX_ATMARP_SIZE + RFC1483LLC_LEN + 3) & ~3; if (atomic_read(&vcc->tx_inuse) && !atm_may_send(vcc, allocated_size)) { DPRINTK("Sorry: tx_inuse = %d, size = %d, sndbuf = %d\n", atomic_read(&vcc->tx_inuse), allocated_size, vcc->sk->sndbuf); return -1; } if(!(skb = alloc_skb(allocated_size, GFP_ATOMIC))) return -1; DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->tx_inuse), skb->truesize); atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); skb->dev = NULL; /* for paths shared with net_device interfaces */ ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = vcc->atm_options; buff = skb->data; memcpy(buff, llc_oui_arp, RFC1483LLC_LEN); hdr = (struct atmarphdr *) (buff + RFC1483LLC_LEN); memset(hdr, 0, MAX_ATMARP_SIZE); hdr->ar_hrd = htons(ARPHRD_ATM); hdr->ar_pro = htons(ETH_P_IP); hdr->ar_op = htons(op); local_ip = clip_vcc_to_local_ip(CLIP_VCC(vcc)); size = hdr->data - buff; /* XXX: htonl might be needed */ memcpy(hdr->data, &local_ip, sizeof(u32)); hdr->ar_spln = sizeof(u32); size += sizeof(u32); if (remote_ip) { /* XXX: htonl might be needed */ memcpy(hdr->data + sizeof(u32), &remote_ip, sizeof(u32)); hdr->ar_tpln = sizeof(u32); size += sizeof(u32); } skb_put(skb, size); if (allocated_size != size) memset(skb->data + size, 0, allocated_size - size); error = vcc->dev->ops->send(vcc,skb); return error ? error : size; }
static int clip_setentry(struct atm_vcc *vcc,u32 ip) { struct neighbour *neigh; struct atmarp_entry *entry; int error; struct clip_vcc *clip_vcc; #ifndef __TCS__ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = 1 } } }; struct rtable *rt; #else struct rtable *rt; struct flowi fl; memset(&fl,0,sizeof(fl)); fl.nl_u.ip4_u.daddr=ip; fl.nl_u.ip4_u.tos=1; #endif if (vcc->push != clip_push) { printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n"); return -EBADF; } clip_vcc = CLIP_VCC(vcc); if (!ip) { if (!clip_vcc->entry) { printk(KERN_ERR "hiding hidden ATMARP entry\n"); return 0; } DPRINTK("setentry: remove\n"); unlink_clip_vcc(clip_vcc); return 0; } error = ip_route_output_key(&rt,&fl); if (error) return error; neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1); ip_rt_put(rt); if (!neigh) return -ENOMEM; entry = NEIGH2ENTRY(neigh); if (entry != clip_vcc->entry) { if (!clip_vcc->entry) DPRINTK("setentry: add\n"); else { DPRINTK("setentry: update\n"); unlink_clip_vcc(clip_vcc); } link_vcc(clip_vcc,entry); } error = neigh_update(neigh, llc_oui, NUD_PERMANENT, NEIGH_UPDATE_F_OVERRIDE|NEIGH_UPDATE_F_ADMIN); neigh_release(neigh); return error; }
static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb) { struct clip_vcc *clip_vcc = CLIP_VCC(vcc); pr_debug("\n"); if (!clip_devs) { atm_return(vcc, skb->truesize); kfree_skb(skb); return; } if (!skb) { pr_debug("removing VCC %p\n", clip_vcc); if (clip_vcc->entry) unlink_clip_vcc(clip_vcc); clip_vcc->old_push(vcc, NULL); /* pass on the bad news */ kfree(clip_vcc); return; } atm_return(vcc, skb->truesize); skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs; /* clip_vcc->entry == NULL if we don't have an IP address yet */ if (!skb->dev) { dev_kfree_skb_any(skb); return; } ATM_SKB(skb)->vcc = vcc; skb_reset_mac_header(skb); if (!clip_vcc->encap || skb->len < RFC1483LLC_LEN || memcmp(skb->data, llc_oui, sizeof(llc_oui))) skb->protocol = htons(ETH_P_IP); else { skb->protocol = ((__be16 *)skb->data)[3]; skb_pull(skb, RFC1483LLC_LEN); if (skb->protocol == htons(ETH_P_ARP)) { skb->dev->stats.rx_packets++; skb->dev->stats.rx_bytes += skb->len; clip_arp_rcv(skb); return; } } clip_vcc->last_use = jiffies; skb->dev->stats.rx_packets++; skb->dev->stats.rx_bytes += skb->len; memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(skb); }
static int clip_arp_rcv(struct sk_buff *skb) { struct atm_vcc *vcc; DPRINTK("clip_arp_rcv\n"); vcc = ATM_SKB(skb)->vcc; if (!vcc) goto Exit; incoming_arp(CLIP_VCC(vcc), (struct atmarphdr *)skb->data, skb->len); Exit: dev_kfree_skb_any(skb); return 0; }
static void clip_pop(struct atm_vcc *vcc,struct sk_buff *skb) { struct clip_vcc *clip_vcc = CLIP_VCC(vcc); struct net_device *dev = skb->dev; int old; unsigned long flags; DPRINTK("clip_pop(vcc %p)\n",vcc); clip_vcc->old_pop(vcc,skb); /* skb->dev == NULL in outbound ARP packets */ if (!dev) return; spin_lock_irqsave(&PRIV(dev)->xoff_lock,flags); if (atm_may_send(vcc,0)) { old = xchg(&clip_vcc->xoff,0); if (old) netif_wake_queue(dev); } spin_unlock_irqrestore(&PRIV(dev)->xoff_lock,flags); }
static int clip_setentry(struct atm_vcc *vcc, __be32 ip) { struct neighbour *neigh; struct atmarp_entry *entry; int error; struct clip_vcc *clip_vcc; struct rtable *rt; if (vcc->push != clip_push) { pr_warning("non-CLIP VCC\n"); return -EBADF; } clip_vcc = CLIP_VCC(vcc); if (!ip) { if (!clip_vcc->entry) { pr_err("hiding hidden ATMARP entry\n"); return 0; } pr_debug("remove\n"); unlink_clip_vcc(clip_vcc); return 0; } rt = ip_route_output(&init_net, ip, 0, 1, 0); if (IS_ERR(rt)) return PTR_ERR(rt); neigh = __neigh_lookup(&arp_tbl, &ip, rt->dst.dev, 1); ip_rt_put(rt); if (!neigh) return -ENOMEM; entry = neighbour_priv(neigh); if (entry != clip_vcc->entry) { if (!clip_vcc->entry) pr_debug("add\n"); else { pr_debug("update\n"); unlink_clip_vcc(clip_vcc); } link_vcc(clip_vcc, entry); } error = neigh_update(neigh, llc_oui, NUD_PERMANENT, NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN); neigh_release(neigh); return error; }
int clip_setentry(struct atm_vcc *vcc,u32 ip) { struct neighbour *neigh; struct atmarp_entry *entry; int error; struct clip_vcc *clip_vcc; struct rtable *rt; if (vcc->push != clip_push) { printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n"); return -EBADF; } clip_vcc = CLIP_VCC(vcc); if (!ip) { if (!clip_vcc->entry) { printk(KERN_ERR "hiding hidden ATMARP entry\n"); return 0; } DPRINTK("setentry: remove\n"); unlink_clip_vcc(clip_vcc); return 0; } error = ip_route_output(&rt,ip,0,1,0); if (error) return error; neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1); ip_rt_put(rt); if (!neigh) return -ENOMEM; entry = NEIGH2ENTRY(neigh); if (entry != clip_vcc->entry) { if (!clip_vcc->entry) DPRINTK("setentry: add\n"); else { DPRINTK("setentry: update\n"); unlink_clip_vcc(clip_vcc); } link_vcc(clip_vcc,entry); } error = neigh_update(neigh,llc_oui,NUD_PERMANENT,1,0); neigh_release(neigh); return error; }
void clip_push(struct atm_vcc *vcc,struct sk_buff *skb) { struct clip_vcc *clip_vcc = CLIP_VCC(vcc); DPRINTK("clip push\n"); if (!skb) { clip_vcc_remove(clip_vcc); return; } atm_return(vcc, skb->truesize); skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs; /* clip_vcc->entry == NULL if we don't have an IP address yet */ if (!skb->dev) { dev_kfree_skb_any(skb); return; } ATM_SKB(skb)->vcc = vcc; skb->mac.raw = skb->data; if (!clip_vcc->encap || skb->len < RFC1483LLC_LEN || memcmp(skb->data, llc_oui, sizeof(llc_oui))) skb->protocol = htons(ETH_P_IP); else { skb->protocol = ((u16 *) skb->data)[3]; skb_pull(skb, RFC1483LLC_LEN); if (skb->protocol == htons(ETH_P_ARP)) { PRIV(skb->dev)->stats.rx_packets++; PRIV(skb->dev)->stats.rx_bytes += skb->len; clip_arp_rcv(skb); return; } } clip_vcc->last_use = jiffies; PRIV(skb->dev)->stats.rx_packets++; PRIV(skb->dev)->stats.rx_bytes += skb->len; netif_rx(skb); }
static int clip_encap(struct atm_vcc *vcc,int mode) { CLIP_VCC(vcc)->encap = mode; return 0; }