📄 clip.c
字号:
struct atm_vcc *vcc; int old; unsigned long flags; DPRINTK("clip_start_xmit (skb %p)\n",skb); if (!skb->dst) { printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n"); dev_kfree_skb(skb); clip_priv->stats.tx_dropped++; return 0; } if (!skb->dst->neighbour) {#if 0 skb->dst->neighbour = clip_find_neighbour(skb->dst,1); if (!skb->dst->neighbour) { dev_kfree_skb(skb); /* lost that one */ clip_priv->stats.tx_dropped++; return 0; }#endif printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n"); dev_kfree_skb(skb); clip_priv->stats.tx_dropped++; return 0; } entry = NEIGH2ENTRY(skb->dst->neighbour); if (!entry->vccs) { if (time_after(jiffies, entry->expires)) { /* should be resolved */ entry->expires = jiffies+ATMARP_RETRY_DELAY*HZ; to_atmarpd(act_need,PRIV(dev)->number,entry->ip); } if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS) skb_queue_tail(&entry->neigh->arp_queue,skb); else { dev_kfree_skb(skb); clip_priv->stats.tx_dropped++; } return 0; } DPRINTK("neigh %p, vccs %p\n",entry,entry->vccs); ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; DPRINTK("using neighbour %p, vcc %p\n",skb->dst->neighbour,vcc); if (entry->vccs->encap) { void *here; here = skb_push(skb,RFC1483LLC_LEN); memcpy(here,llc_oui,sizeof(llc_oui)); ((u16 *) here)[3] = skb->protocol; } atomic_add(skb->truesize,&vcc->tx_inuse); ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = vcc->atm_options; entry->vccs->last_use = jiffies; DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev); old = xchg(&entry->vccs->xoff,1); /* assume XOFF ... */ if (old) { printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n"); return 0; } clip_priv->stats.tx_packets++; clip_priv->stats.tx_bytes += skb->len; (void) vcc->send(vcc,skb); if (atm_may_send(vcc,0)) { entry->vccs->xoff = 0; return 0; } spin_lock_irqsave(&clip_priv->xoff_lock,flags); netif_stop_queue(dev); /* XOFF -> throttle immediately */ barrier(); if (!entry->vccs->xoff) netif_start_queue(dev); /* Oh, we just raced with clip_pop. netif_start_queue should be good enough, because nothing should really be asleep because of the brief netif_stop_queue. If this isn't true or if it changes, use netif_wake_queue instead. */ spin_unlock_irqrestore(&clip_priv->xoff_lock,flags); return 0;}static struct net_device_stats *clip_get_stats(struct net_device *dev){ return &PRIV(dev)->stats;}int clip_mkip(struct atm_vcc *vcc,int timeout){ struct clip_vcc *clip_vcc; struct sk_buff_head copy; struct sk_buff *skb; if (!vcc->push) return -EBADFD; clip_vcc = kmalloc(sizeof(struct clip_vcc),GFP_KERNEL); if (!clip_vcc) return -ENOMEM; DPRINTK("mkip clip_vcc %p vcc %p\n",clip_vcc,vcc); clip_vcc->vcc = vcc; vcc->user_back = clip_vcc; clip_vcc->entry = NULL; clip_vcc->xoff = 0; clip_vcc->encap = 1; clip_vcc->last_use = jiffies; clip_vcc->idle_timeout = timeout*HZ; clip_vcc->old_push = vcc->push; clip_vcc->old_pop = vcc->pop; vcc->push = clip_push; vcc->pop = clip_pop; skb_queue_head_init(©); skb_migrate(&vcc->recvq,©); /* re-process everything received between connection setup and MKIP */ while ((skb = skb_dequeue(©))) if (!clip_devs) { atm_return(vcc,skb->truesize); kfree_skb(skb); } else { unsigned int len = skb->len; clip_push(vcc,skb); PRIV(skb->dev)->stats.rx_packets--; PRIV(skb->dev)->stats.rx_bytes -= len; } return 0;}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;}static int clip_init(struct net_device *dev){ DPRINTK("clip_init %s\n",dev->name); dev->hard_start_xmit = clip_start_xmit; /* sg_xmit ... */ dev->hard_header = NULL; dev->rebuild_header = NULL; dev->set_mac_address = NULL; dev->hard_header_parse = NULL; dev->hard_header_cache = NULL; dev->header_cache_update = NULL; dev->change_mtu = NULL; dev->do_ioctl = NULL; dev->get_stats = clip_get_stats; dev->type = ARPHRD_ATM; dev->hard_header_len = RFC1483LLC_LEN; dev->mtu = RFC1626_MTU; dev->addr_len = 0; dev->tx_queue_len = 100; /* "normal" queue (packets) */ /* When using a "real" qdisc, the qdisc determines the queue */ /* length. tx_queue_len is only used for the default case, */ /* without any more elaborate queuing. 100 is a reasonable */ /* compromise between decent burst-tolerance and protection */ /* against memory hogs. */ dev->flags = 0; return 0;}int clip_create(int number){ struct net_device *dev; struct clip_priv *clip_priv; int error; if (number != -1) { for (dev = clip_devs; dev; dev = PRIV(dev)->next) if (PRIV(dev)->number == number) return -EEXIST; } else { number = 0; for (dev = clip_devs; dev; dev = PRIV(dev)->next) if (PRIV(dev)->number >= number) number = PRIV(dev)->number+1; } dev = kmalloc(sizeof(struct net_device)+sizeof(struct clip_priv), GFP_KERNEL); if (!dev) return -ENOMEM; memset(dev,0,sizeof(struct net_device)+sizeof(struct clip_priv)); clip_priv = PRIV(dev); sprintf(dev->name,"atm%d",number); dev->init = clip_init; spin_lock_init(&clip_priv->xoff_lock); clip_priv->number = number; error = register_netdev(dev); if (error) { kfree(dev); return error; } clip_priv->next = clip_devs; clip_devs = dev; DPRINTK("registered (net:%s)\n",dev->name); return number;}static int clip_device_event(struct notifier_block *this,unsigned long event, void *dev){ /* ignore non-CLIP devices */ if (((struct net_device *) dev)->type != ARPHRD_ATM || ((struct net_device *) dev)->init != clip_init) return NOTIFY_DONE; switch (event) { case NETDEV_UP: DPRINTK("clip_device_event NETDEV_UP\n"); (void) to_atmarpd(act_up,PRIV(dev)->number,0); break; case NETDEV_GOING_DOWN: DPRINTK("clip_device_event NETDEV_DOWN\n"); (void) to_atmarpd(act_down,PRIV(dev)->number,0); break; case NETDEV_CHANGE: case NETDEV_CHANGEMTU: DPRINTK("clip_device_event NETDEV_CHANGE*\n"); (void) to_atmarpd(act_change,PRIV(dev)->number,0); break; case NETDEV_REBOOT: case NETDEV_REGISTER: case NETDEV_DOWN: DPRINTK("clip_device_event %ld\n",event); /* ignore */ break; default: printk(KERN_WARNING "clip_device_event: unknown event " "%ld\n",event); break; } return NOTIFY_DONE;}static int clip_inet_event(struct notifier_block *this,unsigned long event, void *ifa){ struct in_device *in_dev; in_dev = ((struct in_ifaddr *) ifa)->ifa_dev; if (!in_dev || !in_dev->dev) { printk(KERN_WARNING "clip_inet_event: no device\n"); return NOTIFY_DONE; } /* * Transitions are of the down-change-up type, so it's sufficient to * handle the change on up. */ if (event != NETDEV_UP) return NOTIFY_DONE; return clip_device_event(this,NETDEV_CHANGE,in_dev->dev);}static struct notifier_block clip_dev_notifier = { clip_device_event, NULL, 0};static struct notifier_block clip_inet_notifier = { clip_inet_event, NULL, 0};static void atmarpd_close(struct atm_vcc *vcc){ DPRINTK("atmarpd_close\n"); atmarpd = NULL; /* assumed to be atomic */ barrier(); unregister_inetaddr_notifier(&clip_inet_notifier); unregister_netdevice_notifier(&clip_dev_notifier); if (skb_peek(&vcc->recvq)) printk(KERN_ERR "atmarpd_close: closing with requests " "pending\n"); skb_queue_purge(&vcc->recvq); DPRINTK("(done)\n");}static struct atmdev_ops atmarpd_dev_ops = { close: atmarpd_close,};static struct atm_dev atmarpd_dev = { &atmarpd_dev_ops, NULL, /* no PHY */ "arpd", /* type */ 999, /* dummy device number */ NULL,NULL, /* pretend not to have any VCCs */ NULL,NULL, /* no data */ { 0 }, /* no flags */ NULL, /* no local address */ { 0 } /* no ESI, no statistics */};int atm_init_atmarp(struct atm_vcc *vcc){ struct net_device *dev; if (atmarpd) return -EADDRINUSE; if (start_timer) { start_timer = 0; init_timer(&idle_timer); idle_timer.expires = jiffies+CLIP_CHECK_INTERVAL*HZ; idle_timer.function = idle_timer_check; add_timer(&idle_timer); } atmarpd = vcc; set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_READY,&vcc->flags); /* allow replies and avoid getting closed if signaling dies */ bind_vcc(vcc,&atmarpd_dev); vcc->push = NULL; vcc->pop = NULL; /* crash */ vcc->push_oam = NULL; /* crash */ if (register_netdevice_notifier(&clip_dev_notifier)) printk(KERN_ERR "register_netdevice_notifier failed\n"); if (register_inetaddr_notifier(&clip_inet_notifier)) printk(KERN_ERR "register_inetaddr_notifier failed\n"); for (dev = clip_devs; dev; dev = PRIV(dev)->next) if (dev->flags & IFF_UP) (void) to_atmarpd(act_up,PRIV(dev)->number,0); return 0;}void atm_clip_init(void){ clip_tbl.lock = RW_LOCK_UNLOCKED; clip_tbl.kmem_cachep = kmem_cache_create(clip_tbl.id, clip_tbl.entry_size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -