1*1da177e4SLinus Torvalds /* net/atm/clip.c - RFC1577 Classical IP over ATM */ 2*1da177e4SLinus Torvalds 3*1da177e4SLinus Torvalds /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ 4*1da177e4SLinus Torvalds 5*1da177e4SLinus Torvalds 6*1da177e4SLinus Torvalds #include <linux/config.h> 7*1da177e4SLinus Torvalds #include <linux/string.h> 8*1da177e4SLinus Torvalds #include <linux/errno.h> 9*1da177e4SLinus Torvalds #include <linux/kernel.h> /* for UINT_MAX */ 10*1da177e4SLinus Torvalds #include <linux/module.h> 11*1da177e4SLinus Torvalds #include <linux/init.h> 12*1da177e4SLinus Torvalds #include <linux/netdevice.h> 13*1da177e4SLinus Torvalds #include <linux/skbuff.h> 14*1da177e4SLinus Torvalds #include <linux/wait.h> 15*1da177e4SLinus Torvalds #include <linux/timer.h> 16*1da177e4SLinus Torvalds #include <linux/if_arp.h> /* for some manifest constants */ 17*1da177e4SLinus Torvalds #include <linux/notifier.h> 18*1da177e4SLinus Torvalds #include <linux/atm.h> 19*1da177e4SLinus Torvalds #include <linux/atmdev.h> 20*1da177e4SLinus Torvalds #include <linux/atmclip.h> 21*1da177e4SLinus Torvalds #include <linux/atmarp.h> 22*1da177e4SLinus Torvalds #include <linux/ip.h> /* for net/route.h */ 23*1da177e4SLinus Torvalds #include <linux/in.h> /* for struct sockaddr_in */ 24*1da177e4SLinus Torvalds #include <linux/if.h> /* for IFF_UP */ 25*1da177e4SLinus Torvalds #include <linux/inetdevice.h> 26*1da177e4SLinus Torvalds #include <linux/bitops.h> 27*1da177e4SLinus Torvalds #include <linux/proc_fs.h> 28*1da177e4SLinus Torvalds #include <linux/seq_file.h> 29*1da177e4SLinus Torvalds #include <linux/rcupdate.h> 30*1da177e4SLinus Torvalds #include <linux/jhash.h> 31*1da177e4SLinus Torvalds #include <net/route.h> /* for struct rtable and routing */ 32*1da177e4SLinus Torvalds #include <net/icmp.h> /* icmp_send */ 33*1da177e4SLinus Torvalds #include <asm/param.h> /* for HZ */ 34*1da177e4SLinus Torvalds #include <asm/byteorder.h> /* for htons etc. */ 35*1da177e4SLinus Torvalds #include <asm/system.h> /* save/restore_flags */ 36*1da177e4SLinus Torvalds #include <asm/uaccess.h> 37*1da177e4SLinus Torvalds #include <asm/atomic.h> 38*1da177e4SLinus Torvalds 39*1da177e4SLinus Torvalds #include "common.h" 40*1da177e4SLinus Torvalds #include "resources.h" 41*1da177e4SLinus Torvalds #include "ipcommon.h" 42*1da177e4SLinus Torvalds #include <net/atmclip.h> 43*1da177e4SLinus Torvalds 44*1da177e4SLinus Torvalds 45*1da177e4SLinus Torvalds #if 0 46*1da177e4SLinus Torvalds #define DPRINTK(format,args...) printk(format,##args) 47*1da177e4SLinus Torvalds #else 48*1da177e4SLinus Torvalds #define DPRINTK(format,args...) 49*1da177e4SLinus Torvalds #endif 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds static struct net_device *clip_devs; 53*1da177e4SLinus Torvalds static struct atm_vcc *atmarpd; 54*1da177e4SLinus Torvalds static struct neigh_table clip_tbl; 55*1da177e4SLinus Torvalds static struct timer_list idle_timer; 56*1da177e4SLinus Torvalds static int start_timer = 1; 57*1da177e4SLinus Torvalds 58*1da177e4SLinus Torvalds 59*1da177e4SLinus Torvalds static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip) 60*1da177e4SLinus Torvalds { 61*1da177e4SLinus Torvalds struct sock *sk; 62*1da177e4SLinus Torvalds struct atmarp_ctrl *ctrl; 63*1da177e4SLinus Torvalds struct sk_buff *skb; 64*1da177e4SLinus Torvalds 65*1da177e4SLinus Torvalds DPRINTK("to_atmarpd(%d)\n",type); 66*1da177e4SLinus Torvalds if (!atmarpd) return -EUNATCH; 67*1da177e4SLinus Torvalds skb = alloc_skb(sizeof(struct atmarp_ctrl),GFP_ATOMIC); 68*1da177e4SLinus Torvalds if (!skb) return -ENOMEM; 69*1da177e4SLinus Torvalds ctrl = (struct atmarp_ctrl *) skb_put(skb,sizeof(struct atmarp_ctrl)); 70*1da177e4SLinus Torvalds ctrl->type = type; 71*1da177e4SLinus Torvalds ctrl->itf_num = itf; 72*1da177e4SLinus Torvalds ctrl->ip = ip; 73*1da177e4SLinus Torvalds atm_force_charge(atmarpd,skb->truesize); 74*1da177e4SLinus Torvalds 75*1da177e4SLinus Torvalds sk = sk_atm(atmarpd); 76*1da177e4SLinus Torvalds skb_queue_tail(&sk->sk_receive_queue, skb); 77*1da177e4SLinus Torvalds sk->sk_data_ready(sk, skb->len); 78*1da177e4SLinus Torvalds return 0; 79*1da177e4SLinus Torvalds } 80*1da177e4SLinus Torvalds 81*1da177e4SLinus Torvalds 82*1da177e4SLinus Torvalds static void link_vcc(struct clip_vcc *clip_vcc,struct atmarp_entry *entry) 83*1da177e4SLinus Torvalds { 84*1da177e4SLinus Torvalds DPRINTK("link_vcc %p to entry %p (neigh %p)\n",clip_vcc,entry, 85*1da177e4SLinus Torvalds entry->neigh); 86*1da177e4SLinus Torvalds clip_vcc->entry = entry; 87*1da177e4SLinus Torvalds clip_vcc->xoff = 0; /* @@@ may overrun buffer by one packet */ 88*1da177e4SLinus Torvalds clip_vcc->next = entry->vccs; 89*1da177e4SLinus Torvalds entry->vccs = clip_vcc; 90*1da177e4SLinus Torvalds entry->neigh->used = jiffies; 91*1da177e4SLinus Torvalds } 92*1da177e4SLinus Torvalds 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds static void unlink_clip_vcc(struct clip_vcc *clip_vcc) 95*1da177e4SLinus Torvalds { 96*1da177e4SLinus Torvalds struct atmarp_entry *entry = clip_vcc->entry; 97*1da177e4SLinus Torvalds struct clip_vcc **walk; 98*1da177e4SLinus Torvalds 99*1da177e4SLinus Torvalds if (!entry) { 100*1da177e4SLinus Torvalds printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n",clip_vcc); 101*1da177e4SLinus Torvalds return; 102*1da177e4SLinus Torvalds } 103*1da177e4SLinus Torvalds spin_lock_bh(&entry->neigh->dev->xmit_lock); /* block clip_start_xmit() */ 104*1da177e4SLinus Torvalds entry->neigh->used = jiffies; 105*1da177e4SLinus Torvalds for (walk = &entry->vccs; *walk; walk = &(*walk)->next) 106*1da177e4SLinus Torvalds if (*walk == clip_vcc) { 107*1da177e4SLinus Torvalds int error; 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds *walk = clip_vcc->next; /* atomic */ 110*1da177e4SLinus Torvalds clip_vcc->entry = NULL; 111*1da177e4SLinus Torvalds if (clip_vcc->xoff) 112*1da177e4SLinus Torvalds netif_wake_queue(entry->neigh->dev); 113*1da177e4SLinus Torvalds if (entry->vccs) 114*1da177e4SLinus Torvalds goto out; 115*1da177e4SLinus Torvalds entry->expires = jiffies-1; 116*1da177e4SLinus Torvalds /* force resolution or expiration */ 117*1da177e4SLinus Torvalds error = neigh_update(entry->neigh, NULL, NUD_NONE, 118*1da177e4SLinus Torvalds NEIGH_UPDATE_F_ADMIN); 119*1da177e4SLinus Torvalds if (error) 120*1da177e4SLinus Torvalds printk(KERN_CRIT "unlink_clip_vcc: " 121*1da177e4SLinus Torvalds "neigh_update failed with %d\n",error); 122*1da177e4SLinus Torvalds goto out; 123*1da177e4SLinus Torvalds } 124*1da177e4SLinus Torvalds printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc " 125*1da177e4SLinus Torvalds "0x%p)\n",entry,clip_vcc); 126*1da177e4SLinus Torvalds out: 127*1da177e4SLinus Torvalds spin_unlock_bh(&entry->neigh->dev->xmit_lock); 128*1da177e4SLinus Torvalds } 129*1da177e4SLinus Torvalds 130*1da177e4SLinus Torvalds /* The neighbour entry n->lock is held. */ 131*1da177e4SLinus Torvalds static int neigh_check_cb(struct neighbour *n) 132*1da177e4SLinus Torvalds { 133*1da177e4SLinus Torvalds struct atmarp_entry *entry = NEIGH2ENTRY(n); 134*1da177e4SLinus Torvalds struct clip_vcc *cv; 135*1da177e4SLinus Torvalds 136*1da177e4SLinus Torvalds for (cv = entry->vccs; cv; cv = cv->next) { 137*1da177e4SLinus Torvalds unsigned long exp = cv->last_use + cv->idle_timeout; 138*1da177e4SLinus Torvalds 139*1da177e4SLinus Torvalds if (cv->idle_timeout && time_after(jiffies, exp)) { 140*1da177e4SLinus Torvalds DPRINTK("releasing vcc %p->%p of entry %p\n", 141*1da177e4SLinus Torvalds cv, cv->vcc, entry); 142*1da177e4SLinus Torvalds vcc_release_async(cv->vcc, -ETIMEDOUT); 143*1da177e4SLinus Torvalds } 144*1da177e4SLinus Torvalds } 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds if (entry->vccs || time_before(jiffies, entry->expires)) 147*1da177e4SLinus Torvalds return 0; 148*1da177e4SLinus Torvalds 149*1da177e4SLinus Torvalds if (atomic_read(&n->refcnt) > 1) { 150*1da177e4SLinus Torvalds struct sk_buff *skb; 151*1da177e4SLinus Torvalds 152*1da177e4SLinus Torvalds DPRINTK("destruction postponed with ref %d\n", 153*1da177e4SLinus Torvalds atomic_read(&n->refcnt)); 154*1da177e4SLinus Torvalds 155*1da177e4SLinus Torvalds while ((skb = skb_dequeue(&n->arp_queue)) != NULL) 156*1da177e4SLinus Torvalds dev_kfree_skb(skb); 157*1da177e4SLinus Torvalds 158*1da177e4SLinus Torvalds return 0; 159*1da177e4SLinus Torvalds } 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds DPRINTK("expired neigh %p\n",n); 162*1da177e4SLinus Torvalds return 1; 163*1da177e4SLinus Torvalds } 164*1da177e4SLinus Torvalds 165*1da177e4SLinus Torvalds static void idle_timer_check(unsigned long dummy) 166*1da177e4SLinus Torvalds { 167*1da177e4SLinus Torvalds write_lock(&clip_tbl.lock); 168*1da177e4SLinus Torvalds __neigh_for_each_release(&clip_tbl, neigh_check_cb); 169*1da177e4SLinus Torvalds mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ); 170*1da177e4SLinus Torvalds write_unlock(&clip_tbl.lock); 171*1da177e4SLinus Torvalds } 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds static int clip_arp_rcv(struct sk_buff *skb) 174*1da177e4SLinus Torvalds { 175*1da177e4SLinus Torvalds struct atm_vcc *vcc; 176*1da177e4SLinus Torvalds 177*1da177e4SLinus Torvalds DPRINTK("clip_arp_rcv\n"); 178*1da177e4SLinus Torvalds vcc = ATM_SKB(skb)->vcc; 179*1da177e4SLinus Torvalds if (!vcc || !atm_charge(vcc,skb->truesize)) { 180*1da177e4SLinus Torvalds dev_kfree_skb_any(skb); 181*1da177e4SLinus Torvalds return 0; 182*1da177e4SLinus Torvalds } 183*1da177e4SLinus Torvalds DPRINTK("pushing to %p\n",vcc); 184*1da177e4SLinus Torvalds DPRINTK("using %p\n",CLIP_VCC(vcc)->old_push); 185*1da177e4SLinus Torvalds CLIP_VCC(vcc)->old_push(vcc,skb); 186*1da177e4SLinus Torvalds return 0; 187*1da177e4SLinus Torvalds } 188*1da177e4SLinus Torvalds 189*1da177e4SLinus Torvalds static const unsigned char llc_oui[] = { 190*1da177e4SLinus Torvalds 0xaa, /* DSAP: non-ISO */ 191*1da177e4SLinus Torvalds 0xaa, /* SSAP: non-ISO */ 192*1da177e4SLinus Torvalds 0x03, /* Ctrl: Unnumbered Information Command PDU */ 193*1da177e4SLinus Torvalds 0x00, /* OUI: EtherType */ 194*1da177e4SLinus Torvalds 0x00, 195*1da177e4SLinus Torvalds 0x00 }; 196*1da177e4SLinus Torvalds 197*1da177e4SLinus Torvalds static void clip_push(struct atm_vcc *vcc,struct sk_buff *skb) 198*1da177e4SLinus Torvalds { 199*1da177e4SLinus Torvalds struct clip_vcc *clip_vcc = CLIP_VCC(vcc); 200*1da177e4SLinus Torvalds 201*1da177e4SLinus Torvalds DPRINTK("clip push\n"); 202*1da177e4SLinus Torvalds if (!skb) { 203*1da177e4SLinus Torvalds DPRINTK("removing VCC %p\n",clip_vcc); 204*1da177e4SLinus Torvalds if (clip_vcc->entry) unlink_clip_vcc(clip_vcc); 205*1da177e4SLinus Torvalds clip_vcc->old_push(vcc,NULL); /* pass on the bad news */ 206*1da177e4SLinus Torvalds kfree(clip_vcc); 207*1da177e4SLinus Torvalds return; 208*1da177e4SLinus Torvalds } 209*1da177e4SLinus Torvalds atm_return(vcc,skb->truesize); 210*1da177e4SLinus Torvalds skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs; 211*1da177e4SLinus Torvalds /* clip_vcc->entry == NULL if we don't have an IP address yet */ 212*1da177e4SLinus Torvalds if (!skb->dev) { 213*1da177e4SLinus Torvalds dev_kfree_skb_any(skb); 214*1da177e4SLinus Torvalds return; 215*1da177e4SLinus Torvalds } 216*1da177e4SLinus Torvalds ATM_SKB(skb)->vcc = vcc; 217*1da177e4SLinus Torvalds skb->mac.raw = skb->data; 218*1da177e4SLinus Torvalds if (!clip_vcc->encap || skb->len < RFC1483LLC_LEN || memcmp(skb->data, 219*1da177e4SLinus Torvalds llc_oui,sizeof(llc_oui))) skb->protocol = htons(ETH_P_IP); 220*1da177e4SLinus Torvalds else { 221*1da177e4SLinus Torvalds skb->protocol = ((u16 *) skb->data)[3]; 222*1da177e4SLinus Torvalds skb_pull(skb,RFC1483LLC_LEN); 223*1da177e4SLinus Torvalds if (skb->protocol == htons(ETH_P_ARP)) { 224*1da177e4SLinus Torvalds PRIV(skb->dev)->stats.rx_packets++; 225*1da177e4SLinus Torvalds PRIV(skb->dev)->stats.rx_bytes += skb->len; 226*1da177e4SLinus Torvalds clip_arp_rcv(skb); 227*1da177e4SLinus Torvalds return; 228*1da177e4SLinus Torvalds } 229*1da177e4SLinus Torvalds } 230*1da177e4SLinus Torvalds clip_vcc->last_use = jiffies; 231*1da177e4SLinus Torvalds PRIV(skb->dev)->stats.rx_packets++; 232*1da177e4SLinus Torvalds PRIV(skb->dev)->stats.rx_bytes += skb->len; 233*1da177e4SLinus Torvalds memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); 234*1da177e4SLinus Torvalds netif_rx(skb); 235*1da177e4SLinus Torvalds } 236*1da177e4SLinus Torvalds 237*1da177e4SLinus Torvalds 238*1da177e4SLinus Torvalds /* 239*1da177e4SLinus Torvalds * Note: these spinlocks _must_not_ block on non-SMP. The only goal is that 240*1da177e4SLinus Torvalds * clip_pop is atomic with respect to the critical section in clip_start_xmit. 241*1da177e4SLinus Torvalds */ 242*1da177e4SLinus Torvalds 243*1da177e4SLinus Torvalds 244*1da177e4SLinus Torvalds static void clip_pop(struct atm_vcc *vcc,struct sk_buff *skb) 245*1da177e4SLinus Torvalds { 246*1da177e4SLinus Torvalds struct clip_vcc *clip_vcc = CLIP_VCC(vcc); 247*1da177e4SLinus Torvalds struct net_device *dev = skb->dev; 248*1da177e4SLinus Torvalds int old; 249*1da177e4SLinus Torvalds unsigned long flags; 250*1da177e4SLinus Torvalds 251*1da177e4SLinus Torvalds DPRINTK("clip_pop(vcc %p)\n",vcc); 252*1da177e4SLinus Torvalds clip_vcc->old_pop(vcc,skb); 253*1da177e4SLinus Torvalds /* skb->dev == NULL in outbound ARP packets */ 254*1da177e4SLinus Torvalds if (!dev) return; 255*1da177e4SLinus Torvalds spin_lock_irqsave(&PRIV(dev)->xoff_lock,flags); 256*1da177e4SLinus Torvalds if (atm_may_send(vcc,0)) { 257*1da177e4SLinus Torvalds old = xchg(&clip_vcc->xoff,0); 258*1da177e4SLinus Torvalds if (old) netif_wake_queue(dev); 259*1da177e4SLinus Torvalds } 260*1da177e4SLinus Torvalds spin_unlock_irqrestore(&PRIV(dev)->xoff_lock,flags); 261*1da177e4SLinus Torvalds } 262*1da177e4SLinus Torvalds 263*1da177e4SLinus Torvalds 264*1da177e4SLinus Torvalds static void clip_neigh_destroy(struct neighbour *neigh) 265*1da177e4SLinus Torvalds { 266*1da177e4SLinus Torvalds DPRINTK("clip_neigh_destroy (neigh %p)\n",neigh); 267*1da177e4SLinus Torvalds if (NEIGH2ENTRY(neigh)->vccs) 268*1da177e4SLinus Torvalds printk(KERN_CRIT "clip_neigh_destroy: vccs != NULL !!!\n"); 269*1da177e4SLinus Torvalds NEIGH2ENTRY(neigh)->vccs = (void *) 0xdeadbeef; 270*1da177e4SLinus Torvalds } 271*1da177e4SLinus Torvalds 272*1da177e4SLinus Torvalds 273*1da177e4SLinus Torvalds static void clip_neigh_solicit(struct neighbour *neigh,struct sk_buff *skb) 274*1da177e4SLinus Torvalds { 275*1da177e4SLinus Torvalds DPRINTK("clip_neigh_solicit (neigh %p, skb %p)\n",neigh,skb); 276*1da177e4SLinus Torvalds to_atmarpd(act_need,PRIV(neigh->dev)->number,NEIGH2ENTRY(neigh)->ip); 277*1da177e4SLinus Torvalds } 278*1da177e4SLinus Torvalds 279*1da177e4SLinus Torvalds 280*1da177e4SLinus Torvalds static void clip_neigh_error(struct neighbour *neigh,struct sk_buff *skb) 281*1da177e4SLinus Torvalds { 282*1da177e4SLinus Torvalds #ifndef CONFIG_ATM_CLIP_NO_ICMP 283*1da177e4SLinus Torvalds icmp_send(skb,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,0); 284*1da177e4SLinus Torvalds #endif 285*1da177e4SLinus Torvalds kfree_skb(skb); 286*1da177e4SLinus Torvalds } 287*1da177e4SLinus Torvalds 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds static struct neigh_ops clip_neigh_ops = { 290*1da177e4SLinus Torvalds .family = AF_INET, 291*1da177e4SLinus Torvalds .destructor = clip_neigh_destroy, 292*1da177e4SLinus Torvalds .solicit = clip_neigh_solicit, 293*1da177e4SLinus Torvalds .error_report = clip_neigh_error, 294*1da177e4SLinus Torvalds .output = dev_queue_xmit, 295*1da177e4SLinus Torvalds .connected_output = dev_queue_xmit, 296*1da177e4SLinus Torvalds .hh_output = dev_queue_xmit, 297*1da177e4SLinus Torvalds .queue_xmit = dev_queue_xmit, 298*1da177e4SLinus Torvalds }; 299*1da177e4SLinus Torvalds 300*1da177e4SLinus Torvalds 301*1da177e4SLinus Torvalds static int clip_constructor(struct neighbour *neigh) 302*1da177e4SLinus Torvalds { 303*1da177e4SLinus Torvalds struct atmarp_entry *entry = NEIGH2ENTRY(neigh); 304*1da177e4SLinus Torvalds struct net_device *dev = neigh->dev; 305*1da177e4SLinus Torvalds struct in_device *in_dev; 306*1da177e4SLinus Torvalds struct neigh_parms *parms; 307*1da177e4SLinus Torvalds 308*1da177e4SLinus Torvalds DPRINTK("clip_constructor (neigh %p, entry %p)\n",neigh,entry); 309*1da177e4SLinus Torvalds neigh->type = inet_addr_type(entry->ip); 310*1da177e4SLinus Torvalds if (neigh->type != RTN_UNICAST) return -EINVAL; 311*1da177e4SLinus Torvalds 312*1da177e4SLinus Torvalds rcu_read_lock(); 313*1da177e4SLinus Torvalds in_dev = rcu_dereference(__in_dev_get(dev)); 314*1da177e4SLinus Torvalds if (!in_dev) { 315*1da177e4SLinus Torvalds rcu_read_unlock(); 316*1da177e4SLinus Torvalds return -EINVAL; 317*1da177e4SLinus Torvalds } 318*1da177e4SLinus Torvalds 319*1da177e4SLinus Torvalds parms = in_dev->arp_parms; 320*1da177e4SLinus Torvalds __neigh_parms_put(neigh->parms); 321*1da177e4SLinus Torvalds neigh->parms = neigh_parms_clone(parms); 322*1da177e4SLinus Torvalds rcu_read_unlock(); 323*1da177e4SLinus Torvalds 324*1da177e4SLinus Torvalds neigh->ops = &clip_neigh_ops; 325*1da177e4SLinus Torvalds neigh->output = neigh->nud_state & NUD_VALID ? 326*1da177e4SLinus Torvalds neigh->ops->connected_output : neigh->ops->output; 327*1da177e4SLinus Torvalds entry->neigh = neigh; 328*1da177e4SLinus Torvalds entry->vccs = NULL; 329*1da177e4SLinus Torvalds entry->expires = jiffies-1; 330*1da177e4SLinus Torvalds return 0; 331*1da177e4SLinus Torvalds } 332*1da177e4SLinus Torvalds 333*1da177e4SLinus Torvalds static u32 clip_hash(const void *pkey, const struct net_device *dev) 334*1da177e4SLinus Torvalds { 335*1da177e4SLinus Torvalds return jhash_2words(*(u32 *)pkey, dev->ifindex, clip_tbl.hash_rnd); 336*1da177e4SLinus Torvalds } 337*1da177e4SLinus Torvalds 338*1da177e4SLinus Torvalds static struct neigh_table clip_tbl = { 339*1da177e4SLinus Torvalds .family = AF_INET, 340*1da177e4SLinus Torvalds .entry_size = sizeof(struct neighbour)+sizeof(struct atmarp_entry), 341*1da177e4SLinus Torvalds .key_len = 4, 342*1da177e4SLinus Torvalds .hash = clip_hash, 343*1da177e4SLinus Torvalds .constructor = clip_constructor, 344*1da177e4SLinus Torvalds .id = "clip_arp_cache", 345*1da177e4SLinus Torvalds 346*1da177e4SLinus Torvalds /* parameters are copied from ARP ... */ 347*1da177e4SLinus Torvalds .parms = { 348*1da177e4SLinus Torvalds .tbl = &clip_tbl, 349*1da177e4SLinus Torvalds .base_reachable_time = 30 * HZ, 350*1da177e4SLinus Torvalds .retrans_time = 1 * HZ, 351*1da177e4SLinus Torvalds .gc_staletime = 60 * HZ, 352*1da177e4SLinus Torvalds .reachable_time = 30 * HZ, 353*1da177e4SLinus Torvalds .delay_probe_time = 5 * HZ, 354*1da177e4SLinus Torvalds .queue_len = 3, 355*1da177e4SLinus Torvalds .ucast_probes = 3, 356*1da177e4SLinus Torvalds .mcast_probes = 3, 357*1da177e4SLinus Torvalds .anycast_delay = 1 * HZ, 358*1da177e4SLinus Torvalds .proxy_delay = (8 * HZ) / 10, 359*1da177e4SLinus Torvalds .proxy_qlen = 64, 360*1da177e4SLinus Torvalds .locktime = 1 * HZ, 361*1da177e4SLinus Torvalds }, 362*1da177e4SLinus Torvalds .gc_interval = 30 * HZ, 363*1da177e4SLinus Torvalds .gc_thresh1 = 128, 364*1da177e4SLinus Torvalds .gc_thresh2 = 512, 365*1da177e4SLinus Torvalds .gc_thresh3 = 1024, 366*1da177e4SLinus Torvalds }; 367*1da177e4SLinus Torvalds 368*1da177e4SLinus Torvalds 369*1da177e4SLinus Torvalds /* @@@ copy bh locking from arp.c -- need to bh-enable atm code before */ 370*1da177e4SLinus Torvalds 371*1da177e4SLinus Torvalds /* 372*1da177e4SLinus Torvalds * We play with the resolve flag: 0 and 1 have the usual meaning, but -1 means 373*1da177e4SLinus Torvalds * to allocate the neighbour entry but not to ask atmarpd for resolution. Also, 374*1da177e4SLinus Torvalds * don't increment the usage count. This is used to create entries in 375*1da177e4SLinus Torvalds * clip_setentry. 376*1da177e4SLinus Torvalds */ 377*1da177e4SLinus Torvalds 378*1da177e4SLinus Torvalds 379*1da177e4SLinus Torvalds static int clip_encap(struct atm_vcc *vcc,int mode) 380*1da177e4SLinus Torvalds { 381*1da177e4SLinus Torvalds CLIP_VCC(vcc)->encap = mode; 382*1da177e4SLinus Torvalds return 0; 383*1da177e4SLinus Torvalds } 384*1da177e4SLinus Torvalds 385*1da177e4SLinus Torvalds 386*1da177e4SLinus Torvalds static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev) 387*1da177e4SLinus Torvalds { 388*1da177e4SLinus Torvalds struct clip_priv *clip_priv = PRIV(dev); 389*1da177e4SLinus Torvalds struct atmarp_entry *entry; 390*1da177e4SLinus Torvalds struct atm_vcc *vcc; 391*1da177e4SLinus Torvalds int old; 392*1da177e4SLinus Torvalds unsigned long flags; 393*1da177e4SLinus Torvalds 394*1da177e4SLinus Torvalds DPRINTK("clip_start_xmit (skb %p)\n",skb); 395*1da177e4SLinus Torvalds if (!skb->dst) { 396*1da177e4SLinus Torvalds printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n"); 397*1da177e4SLinus Torvalds dev_kfree_skb(skb); 398*1da177e4SLinus Torvalds clip_priv->stats.tx_dropped++; 399*1da177e4SLinus Torvalds return 0; 400*1da177e4SLinus Torvalds } 401*1da177e4SLinus Torvalds if (!skb->dst->neighbour) { 402*1da177e4SLinus Torvalds #if 0 403*1da177e4SLinus Torvalds skb->dst->neighbour = clip_find_neighbour(skb->dst,1); 404*1da177e4SLinus Torvalds if (!skb->dst->neighbour) { 405*1da177e4SLinus Torvalds dev_kfree_skb(skb); /* lost that one */ 406*1da177e4SLinus Torvalds clip_priv->stats.tx_dropped++; 407*1da177e4SLinus Torvalds return 0; 408*1da177e4SLinus Torvalds } 409*1da177e4SLinus Torvalds #endif 410*1da177e4SLinus Torvalds printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n"); 411*1da177e4SLinus Torvalds dev_kfree_skb(skb); 412*1da177e4SLinus Torvalds clip_priv->stats.tx_dropped++; 413*1da177e4SLinus Torvalds return 0; 414*1da177e4SLinus Torvalds } 415*1da177e4SLinus Torvalds entry = NEIGH2ENTRY(skb->dst->neighbour); 416*1da177e4SLinus Torvalds if (!entry->vccs) { 417*1da177e4SLinus Torvalds if (time_after(jiffies, entry->expires)) { 418*1da177e4SLinus Torvalds /* should be resolved */ 419*1da177e4SLinus Torvalds entry->expires = jiffies+ATMARP_RETRY_DELAY*HZ; 420*1da177e4SLinus Torvalds to_atmarpd(act_need,PRIV(dev)->number,entry->ip); 421*1da177e4SLinus Torvalds } 422*1da177e4SLinus Torvalds if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS) 423*1da177e4SLinus Torvalds skb_queue_tail(&entry->neigh->arp_queue,skb); 424*1da177e4SLinus Torvalds else { 425*1da177e4SLinus Torvalds dev_kfree_skb(skb); 426*1da177e4SLinus Torvalds clip_priv->stats.tx_dropped++; 427*1da177e4SLinus Torvalds } 428*1da177e4SLinus Torvalds return 0; 429*1da177e4SLinus Torvalds } 430*1da177e4SLinus Torvalds DPRINTK("neigh %p, vccs %p\n",entry,entry->vccs); 431*1da177e4SLinus Torvalds ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; 432*1da177e4SLinus Torvalds DPRINTK("using neighbour %p, vcc %p\n",skb->dst->neighbour,vcc); 433*1da177e4SLinus Torvalds if (entry->vccs->encap) { 434*1da177e4SLinus Torvalds void *here; 435*1da177e4SLinus Torvalds 436*1da177e4SLinus Torvalds here = skb_push(skb,RFC1483LLC_LEN); 437*1da177e4SLinus Torvalds memcpy(here,llc_oui,sizeof(llc_oui)); 438*1da177e4SLinus Torvalds ((u16 *) here)[3] = skb->protocol; 439*1da177e4SLinus Torvalds } 440*1da177e4SLinus Torvalds atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); 441*1da177e4SLinus Torvalds ATM_SKB(skb)->atm_options = vcc->atm_options; 442*1da177e4SLinus Torvalds entry->vccs->last_use = jiffies; 443*1da177e4SLinus Torvalds DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev); 444*1da177e4SLinus Torvalds old = xchg(&entry->vccs->xoff,1); /* assume XOFF ... */ 445*1da177e4SLinus Torvalds if (old) { 446*1da177e4SLinus Torvalds printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n"); 447*1da177e4SLinus Torvalds return 0; 448*1da177e4SLinus Torvalds } 449*1da177e4SLinus Torvalds clip_priv->stats.tx_packets++; 450*1da177e4SLinus Torvalds clip_priv->stats.tx_bytes += skb->len; 451*1da177e4SLinus Torvalds (void) vcc->send(vcc,skb); 452*1da177e4SLinus Torvalds if (atm_may_send(vcc,0)) { 453*1da177e4SLinus Torvalds entry->vccs->xoff = 0; 454*1da177e4SLinus Torvalds return 0; 455*1da177e4SLinus Torvalds } 456*1da177e4SLinus Torvalds spin_lock_irqsave(&clip_priv->xoff_lock,flags); 457*1da177e4SLinus Torvalds netif_stop_queue(dev); /* XOFF -> throttle immediately */ 458*1da177e4SLinus Torvalds barrier(); 459*1da177e4SLinus Torvalds if (!entry->vccs->xoff) 460*1da177e4SLinus Torvalds netif_start_queue(dev); 461*1da177e4SLinus Torvalds /* Oh, we just raced with clip_pop. netif_start_queue should be 462*1da177e4SLinus Torvalds good enough, because nothing should really be asleep because 463*1da177e4SLinus Torvalds of the brief netif_stop_queue. If this isn't true or if it 464*1da177e4SLinus Torvalds changes, use netif_wake_queue instead. */ 465*1da177e4SLinus Torvalds spin_unlock_irqrestore(&clip_priv->xoff_lock,flags); 466*1da177e4SLinus Torvalds return 0; 467*1da177e4SLinus Torvalds } 468*1da177e4SLinus Torvalds 469*1da177e4SLinus Torvalds 470*1da177e4SLinus Torvalds static struct net_device_stats *clip_get_stats(struct net_device *dev) 471*1da177e4SLinus Torvalds { 472*1da177e4SLinus Torvalds return &PRIV(dev)->stats; 473*1da177e4SLinus Torvalds } 474*1da177e4SLinus Torvalds 475*1da177e4SLinus Torvalds 476*1da177e4SLinus Torvalds static int clip_mkip(struct atm_vcc *vcc,int timeout) 477*1da177e4SLinus Torvalds { 478*1da177e4SLinus Torvalds struct clip_vcc *clip_vcc; 479*1da177e4SLinus Torvalds struct sk_buff_head copy; 480*1da177e4SLinus Torvalds struct sk_buff *skb; 481*1da177e4SLinus Torvalds 482*1da177e4SLinus Torvalds if (!vcc->push) return -EBADFD; 483*1da177e4SLinus Torvalds clip_vcc = kmalloc(sizeof(struct clip_vcc),GFP_KERNEL); 484*1da177e4SLinus Torvalds if (!clip_vcc) return -ENOMEM; 485*1da177e4SLinus Torvalds DPRINTK("mkip clip_vcc %p vcc %p\n",clip_vcc,vcc); 486*1da177e4SLinus Torvalds clip_vcc->vcc = vcc; 487*1da177e4SLinus Torvalds vcc->user_back = clip_vcc; 488*1da177e4SLinus Torvalds set_bit(ATM_VF_IS_CLIP, &vcc->flags); 489*1da177e4SLinus Torvalds clip_vcc->entry = NULL; 490*1da177e4SLinus Torvalds clip_vcc->xoff = 0; 491*1da177e4SLinus Torvalds clip_vcc->encap = 1; 492*1da177e4SLinus Torvalds clip_vcc->last_use = jiffies; 493*1da177e4SLinus Torvalds clip_vcc->idle_timeout = timeout*HZ; 494*1da177e4SLinus Torvalds clip_vcc->old_push = vcc->push; 495*1da177e4SLinus Torvalds clip_vcc->old_pop = vcc->pop; 496*1da177e4SLinus Torvalds vcc->push = clip_push; 497*1da177e4SLinus Torvalds vcc->pop = clip_pop; 498*1da177e4SLinus Torvalds skb_queue_head_init(©); 499*1da177e4SLinus Torvalds skb_migrate(&sk_atm(vcc)->sk_receive_queue, ©); 500*1da177e4SLinus Torvalds /* re-process everything received between connection setup and MKIP */ 501*1da177e4SLinus Torvalds while ((skb = skb_dequeue(©)) != NULL) 502*1da177e4SLinus Torvalds if (!clip_devs) { 503*1da177e4SLinus Torvalds atm_return(vcc,skb->truesize); 504*1da177e4SLinus Torvalds kfree_skb(skb); 505*1da177e4SLinus Torvalds } 506*1da177e4SLinus Torvalds else { 507*1da177e4SLinus Torvalds unsigned int len = skb->len; 508*1da177e4SLinus Torvalds 509*1da177e4SLinus Torvalds clip_push(vcc,skb); 510*1da177e4SLinus Torvalds PRIV(skb->dev)->stats.rx_packets--; 511*1da177e4SLinus Torvalds PRIV(skb->dev)->stats.rx_bytes -= len; 512*1da177e4SLinus Torvalds } 513*1da177e4SLinus Torvalds return 0; 514*1da177e4SLinus Torvalds } 515*1da177e4SLinus Torvalds 516*1da177e4SLinus Torvalds 517*1da177e4SLinus Torvalds static int clip_setentry(struct atm_vcc *vcc,u32 ip) 518*1da177e4SLinus Torvalds { 519*1da177e4SLinus Torvalds struct neighbour *neigh; 520*1da177e4SLinus Torvalds struct atmarp_entry *entry; 521*1da177e4SLinus Torvalds int error; 522*1da177e4SLinus Torvalds struct clip_vcc *clip_vcc; 523*1da177e4SLinus Torvalds struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = 1 } } }; 524*1da177e4SLinus Torvalds struct rtable *rt; 525*1da177e4SLinus Torvalds 526*1da177e4SLinus Torvalds if (vcc->push != clip_push) { 527*1da177e4SLinus Torvalds printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n"); 528*1da177e4SLinus Torvalds return -EBADF; 529*1da177e4SLinus Torvalds } 530*1da177e4SLinus Torvalds clip_vcc = CLIP_VCC(vcc); 531*1da177e4SLinus Torvalds if (!ip) { 532*1da177e4SLinus Torvalds if (!clip_vcc->entry) { 533*1da177e4SLinus Torvalds printk(KERN_ERR "hiding hidden ATMARP entry\n"); 534*1da177e4SLinus Torvalds return 0; 535*1da177e4SLinus Torvalds } 536*1da177e4SLinus Torvalds DPRINTK("setentry: remove\n"); 537*1da177e4SLinus Torvalds unlink_clip_vcc(clip_vcc); 538*1da177e4SLinus Torvalds return 0; 539*1da177e4SLinus Torvalds } 540*1da177e4SLinus Torvalds error = ip_route_output_key(&rt,&fl); 541*1da177e4SLinus Torvalds if (error) return error; 542*1da177e4SLinus Torvalds neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1); 543*1da177e4SLinus Torvalds ip_rt_put(rt); 544*1da177e4SLinus Torvalds if (!neigh) 545*1da177e4SLinus Torvalds return -ENOMEM; 546*1da177e4SLinus Torvalds entry = NEIGH2ENTRY(neigh); 547*1da177e4SLinus Torvalds if (entry != clip_vcc->entry) { 548*1da177e4SLinus Torvalds if (!clip_vcc->entry) DPRINTK("setentry: add\n"); 549*1da177e4SLinus Torvalds else { 550*1da177e4SLinus Torvalds DPRINTK("setentry: update\n"); 551*1da177e4SLinus Torvalds unlink_clip_vcc(clip_vcc); 552*1da177e4SLinus Torvalds } 553*1da177e4SLinus Torvalds link_vcc(clip_vcc,entry); 554*1da177e4SLinus Torvalds } 555*1da177e4SLinus Torvalds error = neigh_update(neigh, llc_oui, NUD_PERMANENT, 556*1da177e4SLinus Torvalds NEIGH_UPDATE_F_OVERRIDE|NEIGH_UPDATE_F_ADMIN); 557*1da177e4SLinus Torvalds neigh_release(neigh); 558*1da177e4SLinus Torvalds return error; 559*1da177e4SLinus Torvalds } 560*1da177e4SLinus Torvalds 561*1da177e4SLinus Torvalds 562*1da177e4SLinus Torvalds static void clip_setup(struct net_device *dev) 563*1da177e4SLinus Torvalds { 564*1da177e4SLinus Torvalds dev->hard_start_xmit = clip_start_xmit; 565*1da177e4SLinus Torvalds /* sg_xmit ... */ 566*1da177e4SLinus Torvalds dev->get_stats = clip_get_stats; 567*1da177e4SLinus Torvalds dev->type = ARPHRD_ATM; 568*1da177e4SLinus Torvalds dev->hard_header_len = RFC1483LLC_LEN; 569*1da177e4SLinus Torvalds dev->mtu = RFC1626_MTU; 570*1da177e4SLinus Torvalds dev->tx_queue_len = 100; /* "normal" queue (packets) */ 571*1da177e4SLinus Torvalds /* When using a "real" qdisc, the qdisc determines the queue */ 572*1da177e4SLinus Torvalds /* length. tx_queue_len is only used for the default case, */ 573*1da177e4SLinus Torvalds /* without any more elaborate queuing. 100 is a reasonable */ 574*1da177e4SLinus Torvalds /* compromise between decent burst-tolerance and protection */ 575*1da177e4SLinus Torvalds /* against memory hogs. */ 576*1da177e4SLinus Torvalds } 577*1da177e4SLinus Torvalds 578*1da177e4SLinus Torvalds 579*1da177e4SLinus Torvalds static int clip_create(int number) 580*1da177e4SLinus Torvalds { 581*1da177e4SLinus Torvalds struct net_device *dev; 582*1da177e4SLinus Torvalds struct clip_priv *clip_priv; 583*1da177e4SLinus Torvalds int error; 584*1da177e4SLinus Torvalds 585*1da177e4SLinus Torvalds if (number != -1) { 586*1da177e4SLinus Torvalds for (dev = clip_devs; dev; dev = PRIV(dev)->next) 587*1da177e4SLinus Torvalds if (PRIV(dev)->number == number) return -EEXIST; 588*1da177e4SLinus Torvalds } 589*1da177e4SLinus Torvalds else { 590*1da177e4SLinus Torvalds number = 0; 591*1da177e4SLinus Torvalds for (dev = clip_devs; dev; dev = PRIV(dev)->next) 592*1da177e4SLinus Torvalds if (PRIV(dev)->number >= number) 593*1da177e4SLinus Torvalds number = PRIV(dev)->number+1; 594*1da177e4SLinus Torvalds } 595*1da177e4SLinus Torvalds dev = alloc_netdev(sizeof(struct clip_priv), "", clip_setup); 596*1da177e4SLinus Torvalds if (!dev) 597*1da177e4SLinus Torvalds return -ENOMEM; 598*1da177e4SLinus Torvalds clip_priv = PRIV(dev); 599*1da177e4SLinus Torvalds sprintf(dev->name,"atm%d",number); 600*1da177e4SLinus Torvalds spin_lock_init(&clip_priv->xoff_lock); 601*1da177e4SLinus Torvalds clip_priv->number = number; 602*1da177e4SLinus Torvalds error = register_netdev(dev); 603*1da177e4SLinus Torvalds if (error) { 604*1da177e4SLinus Torvalds free_netdev(dev); 605*1da177e4SLinus Torvalds return error; 606*1da177e4SLinus Torvalds } 607*1da177e4SLinus Torvalds clip_priv->next = clip_devs; 608*1da177e4SLinus Torvalds clip_devs = dev; 609*1da177e4SLinus Torvalds DPRINTK("registered (net:%s)\n",dev->name); 610*1da177e4SLinus Torvalds return number; 611*1da177e4SLinus Torvalds } 612*1da177e4SLinus Torvalds 613*1da177e4SLinus Torvalds 614*1da177e4SLinus Torvalds static int clip_device_event(struct notifier_block *this,unsigned long event, 615*1da177e4SLinus Torvalds void *dev) 616*1da177e4SLinus Torvalds { 617*1da177e4SLinus Torvalds /* ignore non-CLIP devices */ 618*1da177e4SLinus Torvalds if (((struct net_device *) dev)->type != ARPHRD_ATM || 619*1da177e4SLinus Torvalds ((struct net_device *) dev)->hard_start_xmit != clip_start_xmit) 620*1da177e4SLinus Torvalds return NOTIFY_DONE; 621*1da177e4SLinus Torvalds switch (event) { 622*1da177e4SLinus Torvalds case NETDEV_UP: 623*1da177e4SLinus Torvalds DPRINTK("clip_device_event NETDEV_UP\n"); 624*1da177e4SLinus Torvalds (void) to_atmarpd(act_up,PRIV(dev)->number,0); 625*1da177e4SLinus Torvalds break; 626*1da177e4SLinus Torvalds case NETDEV_GOING_DOWN: 627*1da177e4SLinus Torvalds DPRINTK("clip_device_event NETDEV_DOWN\n"); 628*1da177e4SLinus Torvalds (void) to_atmarpd(act_down,PRIV(dev)->number,0); 629*1da177e4SLinus Torvalds break; 630*1da177e4SLinus Torvalds case NETDEV_CHANGE: 631*1da177e4SLinus Torvalds case NETDEV_CHANGEMTU: 632*1da177e4SLinus Torvalds DPRINTK("clip_device_event NETDEV_CHANGE*\n"); 633*1da177e4SLinus Torvalds (void) to_atmarpd(act_change,PRIV(dev)->number,0); 634*1da177e4SLinus Torvalds break; 635*1da177e4SLinus Torvalds case NETDEV_REBOOT: 636*1da177e4SLinus Torvalds case NETDEV_REGISTER: 637*1da177e4SLinus Torvalds case NETDEV_DOWN: 638*1da177e4SLinus Torvalds DPRINTK("clip_device_event %ld\n",event); 639*1da177e4SLinus Torvalds /* ignore */ 640*1da177e4SLinus Torvalds break; 641*1da177e4SLinus Torvalds default: 642*1da177e4SLinus Torvalds printk(KERN_WARNING "clip_device_event: unknown event " 643*1da177e4SLinus Torvalds "%ld\n",event); 644*1da177e4SLinus Torvalds break; 645*1da177e4SLinus Torvalds } 646*1da177e4SLinus Torvalds return NOTIFY_DONE; 647*1da177e4SLinus Torvalds } 648*1da177e4SLinus Torvalds 649*1da177e4SLinus Torvalds 650*1da177e4SLinus Torvalds static int clip_inet_event(struct notifier_block *this,unsigned long event, 651*1da177e4SLinus Torvalds void *ifa) 652*1da177e4SLinus Torvalds { 653*1da177e4SLinus Torvalds struct in_device *in_dev; 654*1da177e4SLinus Torvalds 655*1da177e4SLinus Torvalds in_dev = ((struct in_ifaddr *) ifa)->ifa_dev; 656*1da177e4SLinus Torvalds if (!in_dev || !in_dev->dev) { 657*1da177e4SLinus Torvalds printk(KERN_WARNING "clip_inet_event: no device\n"); 658*1da177e4SLinus Torvalds return NOTIFY_DONE; 659*1da177e4SLinus Torvalds } 660*1da177e4SLinus Torvalds /* 661*1da177e4SLinus Torvalds * Transitions are of the down-change-up type, so it's sufficient to 662*1da177e4SLinus Torvalds * handle the change on up. 663*1da177e4SLinus Torvalds */ 664*1da177e4SLinus Torvalds if (event != NETDEV_UP) return NOTIFY_DONE; 665*1da177e4SLinus Torvalds return clip_device_event(this,NETDEV_CHANGE,in_dev->dev); 666*1da177e4SLinus Torvalds } 667*1da177e4SLinus Torvalds 668*1da177e4SLinus Torvalds 669*1da177e4SLinus Torvalds static struct notifier_block clip_dev_notifier = { 670*1da177e4SLinus Torvalds clip_device_event, 671*1da177e4SLinus Torvalds NULL, 672*1da177e4SLinus Torvalds 0 673*1da177e4SLinus Torvalds }; 674*1da177e4SLinus Torvalds 675*1da177e4SLinus Torvalds 676*1da177e4SLinus Torvalds 677*1da177e4SLinus Torvalds static struct notifier_block clip_inet_notifier = { 678*1da177e4SLinus Torvalds clip_inet_event, 679*1da177e4SLinus Torvalds NULL, 680*1da177e4SLinus Torvalds 0 681*1da177e4SLinus Torvalds }; 682*1da177e4SLinus Torvalds 683*1da177e4SLinus Torvalds 684*1da177e4SLinus Torvalds 685*1da177e4SLinus Torvalds static void atmarpd_close(struct atm_vcc *vcc) 686*1da177e4SLinus Torvalds { 687*1da177e4SLinus Torvalds DPRINTK("atmarpd_close\n"); 688*1da177e4SLinus Torvalds atmarpd = NULL; /* assumed to be atomic */ 689*1da177e4SLinus Torvalds barrier(); 690*1da177e4SLinus Torvalds unregister_inetaddr_notifier(&clip_inet_notifier); 691*1da177e4SLinus Torvalds unregister_netdevice_notifier(&clip_dev_notifier); 692*1da177e4SLinus Torvalds if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) 693*1da177e4SLinus Torvalds printk(KERN_ERR "atmarpd_close: closing with requests " 694*1da177e4SLinus Torvalds "pending\n"); 695*1da177e4SLinus Torvalds skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); 696*1da177e4SLinus Torvalds DPRINTK("(done)\n"); 697*1da177e4SLinus Torvalds module_put(THIS_MODULE); 698*1da177e4SLinus Torvalds } 699*1da177e4SLinus Torvalds 700*1da177e4SLinus Torvalds 701*1da177e4SLinus Torvalds static struct atmdev_ops atmarpd_dev_ops = { 702*1da177e4SLinus Torvalds .close = atmarpd_close 703*1da177e4SLinus Torvalds }; 704*1da177e4SLinus Torvalds 705*1da177e4SLinus Torvalds 706*1da177e4SLinus Torvalds static struct atm_dev atmarpd_dev = { 707*1da177e4SLinus Torvalds .ops = &atmarpd_dev_ops, 708*1da177e4SLinus Torvalds .type = "arpd", 709*1da177e4SLinus Torvalds .number = 999, 710*1da177e4SLinus Torvalds .lock = SPIN_LOCK_UNLOCKED 711*1da177e4SLinus Torvalds }; 712*1da177e4SLinus Torvalds 713*1da177e4SLinus Torvalds 714*1da177e4SLinus Torvalds static int atm_init_atmarp(struct atm_vcc *vcc) 715*1da177e4SLinus Torvalds { 716*1da177e4SLinus Torvalds if (atmarpd) return -EADDRINUSE; 717*1da177e4SLinus Torvalds if (start_timer) { 718*1da177e4SLinus Torvalds start_timer = 0; 719*1da177e4SLinus Torvalds init_timer(&idle_timer); 720*1da177e4SLinus Torvalds idle_timer.expires = jiffies+CLIP_CHECK_INTERVAL*HZ; 721*1da177e4SLinus Torvalds idle_timer.function = idle_timer_check; 722*1da177e4SLinus Torvalds add_timer(&idle_timer); 723*1da177e4SLinus Torvalds } 724*1da177e4SLinus Torvalds atmarpd = vcc; 725*1da177e4SLinus Torvalds set_bit(ATM_VF_META,&vcc->flags); 726*1da177e4SLinus Torvalds set_bit(ATM_VF_READY,&vcc->flags); 727*1da177e4SLinus Torvalds /* allow replies and avoid getting closed if signaling dies */ 728*1da177e4SLinus Torvalds vcc->dev = &atmarpd_dev; 729*1da177e4SLinus Torvalds vcc_insert_socket(sk_atm(vcc)); 730*1da177e4SLinus Torvalds vcc->push = NULL; 731*1da177e4SLinus Torvalds vcc->pop = NULL; /* crash */ 732*1da177e4SLinus Torvalds vcc->push_oam = NULL; /* crash */ 733*1da177e4SLinus Torvalds if (register_netdevice_notifier(&clip_dev_notifier)) 734*1da177e4SLinus Torvalds printk(KERN_ERR "register_netdevice_notifier failed\n"); 735*1da177e4SLinus Torvalds if (register_inetaddr_notifier(&clip_inet_notifier)) 736*1da177e4SLinus Torvalds printk(KERN_ERR "register_inetaddr_notifier failed\n"); 737*1da177e4SLinus Torvalds return 0; 738*1da177e4SLinus Torvalds } 739*1da177e4SLinus Torvalds 740*1da177e4SLinus Torvalds static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 741*1da177e4SLinus Torvalds { 742*1da177e4SLinus Torvalds struct atm_vcc *vcc = ATM_SD(sock); 743*1da177e4SLinus Torvalds int err = 0; 744*1da177e4SLinus Torvalds 745*1da177e4SLinus Torvalds switch (cmd) { 746*1da177e4SLinus Torvalds case SIOCMKCLIP: 747*1da177e4SLinus Torvalds case ATMARPD_CTRL: 748*1da177e4SLinus Torvalds case ATMARP_MKIP: 749*1da177e4SLinus Torvalds case ATMARP_SETENTRY: 750*1da177e4SLinus Torvalds case ATMARP_ENCAP: 751*1da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 752*1da177e4SLinus Torvalds return -EPERM; 753*1da177e4SLinus Torvalds break; 754*1da177e4SLinus Torvalds default: 755*1da177e4SLinus Torvalds return -ENOIOCTLCMD; 756*1da177e4SLinus Torvalds } 757*1da177e4SLinus Torvalds 758*1da177e4SLinus Torvalds switch (cmd) { 759*1da177e4SLinus Torvalds case SIOCMKCLIP: 760*1da177e4SLinus Torvalds err = clip_create(arg); 761*1da177e4SLinus Torvalds break; 762*1da177e4SLinus Torvalds case ATMARPD_CTRL: 763*1da177e4SLinus Torvalds err = atm_init_atmarp(vcc); 764*1da177e4SLinus Torvalds if (!err) { 765*1da177e4SLinus Torvalds sock->state = SS_CONNECTED; 766*1da177e4SLinus Torvalds __module_get(THIS_MODULE); 767*1da177e4SLinus Torvalds } 768*1da177e4SLinus Torvalds break; 769*1da177e4SLinus Torvalds case ATMARP_MKIP: 770*1da177e4SLinus Torvalds err = clip_mkip(vcc ,arg); 771*1da177e4SLinus Torvalds break; 772*1da177e4SLinus Torvalds case ATMARP_SETENTRY: 773*1da177e4SLinus Torvalds err = clip_setentry(vcc, arg); 774*1da177e4SLinus Torvalds break; 775*1da177e4SLinus Torvalds case ATMARP_ENCAP: 776*1da177e4SLinus Torvalds err = clip_encap(vcc, arg); 777*1da177e4SLinus Torvalds break; 778*1da177e4SLinus Torvalds } 779*1da177e4SLinus Torvalds return err; 780*1da177e4SLinus Torvalds } 781*1da177e4SLinus Torvalds 782*1da177e4SLinus Torvalds static struct atm_ioctl clip_ioctl_ops = { 783*1da177e4SLinus Torvalds .owner = THIS_MODULE, 784*1da177e4SLinus Torvalds .ioctl = clip_ioctl, 785*1da177e4SLinus Torvalds }; 786*1da177e4SLinus Torvalds 787*1da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 788*1da177e4SLinus Torvalds 789*1da177e4SLinus Torvalds static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr) 790*1da177e4SLinus Torvalds { 791*1da177e4SLinus Torvalds static int code[] = { 1,2,10,6,1,0 }; 792*1da177e4SLinus Torvalds static int e164[] = { 1,8,4,6,1,0 }; 793*1da177e4SLinus Torvalds 794*1da177e4SLinus Torvalds if (*addr->sas_addr.pub) { 795*1da177e4SLinus Torvalds seq_printf(seq, "%s", addr->sas_addr.pub); 796*1da177e4SLinus Torvalds if (*addr->sas_addr.prv) 797*1da177e4SLinus Torvalds seq_putc(seq, '+'); 798*1da177e4SLinus Torvalds } else if (!*addr->sas_addr.prv) { 799*1da177e4SLinus Torvalds seq_printf(seq, "%s", "(none)"); 800*1da177e4SLinus Torvalds return; 801*1da177e4SLinus Torvalds } 802*1da177e4SLinus Torvalds if (*addr->sas_addr.prv) { 803*1da177e4SLinus Torvalds unsigned char *prv = addr->sas_addr.prv; 804*1da177e4SLinus Torvalds int *fields; 805*1da177e4SLinus Torvalds int i, j; 806*1da177e4SLinus Torvalds 807*1da177e4SLinus Torvalds fields = *prv == ATM_AFI_E164 ? e164 : code; 808*1da177e4SLinus Torvalds for (i = 0; fields[i]; i++) { 809*1da177e4SLinus Torvalds for (j = fields[i]; j; j--) 810*1da177e4SLinus Torvalds seq_printf(seq, "%02X", *prv++); 811*1da177e4SLinus Torvalds if (fields[i+1]) 812*1da177e4SLinus Torvalds seq_putc(seq, '.'); 813*1da177e4SLinus Torvalds } 814*1da177e4SLinus Torvalds } 815*1da177e4SLinus Torvalds } 816*1da177e4SLinus Torvalds 817*1da177e4SLinus Torvalds /* This means the neighbour entry has no attached VCC objects. */ 818*1da177e4SLinus Torvalds #define SEQ_NO_VCC_TOKEN ((void *) 2) 819*1da177e4SLinus Torvalds 820*1da177e4SLinus Torvalds static void atmarp_info(struct seq_file *seq, struct net_device *dev, 821*1da177e4SLinus Torvalds struct atmarp_entry *entry, struct clip_vcc *clip_vcc) 822*1da177e4SLinus Torvalds { 823*1da177e4SLinus Torvalds unsigned long exp; 824*1da177e4SLinus Torvalds char buf[17]; 825*1da177e4SLinus Torvalds int svc, llc, off; 826*1da177e4SLinus Torvalds 827*1da177e4SLinus Torvalds svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) || 828*1da177e4SLinus Torvalds (sk_atm(clip_vcc->vcc)->sk_family == AF_ATMSVC)); 829*1da177e4SLinus Torvalds 830*1da177e4SLinus Torvalds llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) || 831*1da177e4SLinus Torvalds clip_vcc->encap); 832*1da177e4SLinus Torvalds 833*1da177e4SLinus Torvalds if (clip_vcc == SEQ_NO_VCC_TOKEN) 834*1da177e4SLinus Torvalds exp = entry->neigh->used; 835*1da177e4SLinus Torvalds else 836*1da177e4SLinus Torvalds exp = clip_vcc->last_use; 837*1da177e4SLinus Torvalds 838*1da177e4SLinus Torvalds exp = (jiffies - exp) / HZ; 839*1da177e4SLinus Torvalds 840*1da177e4SLinus Torvalds seq_printf(seq, "%-6s%-4s%-4s%5ld ", 841*1da177e4SLinus Torvalds dev->name, 842*1da177e4SLinus Torvalds svc ? "SVC" : "PVC", 843*1da177e4SLinus Torvalds llc ? "LLC" : "NULL", 844*1da177e4SLinus Torvalds exp); 845*1da177e4SLinus Torvalds 846*1da177e4SLinus Torvalds off = scnprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d", 847*1da177e4SLinus Torvalds NIPQUAD(entry->ip)); 848*1da177e4SLinus Torvalds while (off < 16) 849*1da177e4SLinus Torvalds buf[off++] = ' '; 850*1da177e4SLinus Torvalds buf[off] = '\0'; 851*1da177e4SLinus Torvalds seq_printf(seq, "%s", buf); 852*1da177e4SLinus Torvalds 853*1da177e4SLinus Torvalds if (clip_vcc == SEQ_NO_VCC_TOKEN) { 854*1da177e4SLinus Torvalds if (time_before(jiffies, entry->expires)) 855*1da177e4SLinus Torvalds seq_printf(seq, "(resolving)\n"); 856*1da177e4SLinus Torvalds else 857*1da177e4SLinus Torvalds seq_printf(seq, "(expired, ref %d)\n", 858*1da177e4SLinus Torvalds atomic_read(&entry->neigh->refcnt)); 859*1da177e4SLinus Torvalds } else if (!svc) { 860*1da177e4SLinus Torvalds seq_printf(seq, "%d.%d.%d\n", 861*1da177e4SLinus Torvalds clip_vcc->vcc->dev->number, 862*1da177e4SLinus Torvalds clip_vcc->vcc->vpi, 863*1da177e4SLinus Torvalds clip_vcc->vcc->vci); 864*1da177e4SLinus Torvalds } else { 865*1da177e4SLinus Torvalds svc_addr(seq, &clip_vcc->vcc->remote); 866*1da177e4SLinus Torvalds seq_putc(seq, '\n'); 867*1da177e4SLinus Torvalds } 868*1da177e4SLinus Torvalds } 869*1da177e4SLinus Torvalds 870*1da177e4SLinus Torvalds struct clip_seq_state { 871*1da177e4SLinus Torvalds /* This member must be first. */ 872*1da177e4SLinus Torvalds struct neigh_seq_state ns; 873*1da177e4SLinus Torvalds 874*1da177e4SLinus Torvalds /* Local to clip specific iteration. */ 875*1da177e4SLinus Torvalds struct clip_vcc *vcc; 876*1da177e4SLinus Torvalds }; 877*1da177e4SLinus Torvalds 878*1da177e4SLinus Torvalds static struct clip_vcc *clip_seq_next_vcc(struct atmarp_entry *e, 879*1da177e4SLinus Torvalds struct clip_vcc *curr) 880*1da177e4SLinus Torvalds { 881*1da177e4SLinus Torvalds if (!curr) { 882*1da177e4SLinus Torvalds curr = e->vccs; 883*1da177e4SLinus Torvalds if (!curr) 884*1da177e4SLinus Torvalds return SEQ_NO_VCC_TOKEN; 885*1da177e4SLinus Torvalds return curr; 886*1da177e4SLinus Torvalds } 887*1da177e4SLinus Torvalds if (curr == SEQ_NO_VCC_TOKEN) 888*1da177e4SLinus Torvalds return NULL; 889*1da177e4SLinus Torvalds 890*1da177e4SLinus Torvalds curr = curr->next; 891*1da177e4SLinus Torvalds 892*1da177e4SLinus Torvalds return curr; 893*1da177e4SLinus Torvalds } 894*1da177e4SLinus Torvalds 895*1da177e4SLinus Torvalds static void *clip_seq_vcc_walk(struct clip_seq_state *state, 896*1da177e4SLinus Torvalds struct atmarp_entry *e, loff_t *pos) 897*1da177e4SLinus Torvalds { 898*1da177e4SLinus Torvalds struct clip_vcc *vcc = state->vcc; 899*1da177e4SLinus Torvalds 900*1da177e4SLinus Torvalds vcc = clip_seq_next_vcc(e, vcc); 901*1da177e4SLinus Torvalds if (vcc && pos != NULL) { 902*1da177e4SLinus Torvalds while (*pos) { 903*1da177e4SLinus Torvalds vcc = clip_seq_next_vcc(e, vcc); 904*1da177e4SLinus Torvalds if (!vcc) 905*1da177e4SLinus Torvalds break; 906*1da177e4SLinus Torvalds --(*pos); 907*1da177e4SLinus Torvalds } 908*1da177e4SLinus Torvalds } 909*1da177e4SLinus Torvalds state->vcc = vcc; 910*1da177e4SLinus Torvalds 911*1da177e4SLinus Torvalds return vcc; 912*1da177e4SLinus Torvalds } 913*1da177e4SLinus Torvalds 914*1da177e4SLinus Torvalds static void *clip_seq_sub_iter(struct neigh_seq_state *_state, 915*1da177e4SLinus Torvalds struct neighbour *n, loff_t *pos) 916*1da177e4SLinus Torvalds { 917*1da177e4SLinus Torvalds struct clip_seq_state *state = (struct clip_seq_state *) _state; 918*1da177e4SLinus Torvalds 919*1da177e4SLinus Torvalds return clip_seq_vcc_walk(state, NEIGH2ENTRY(n), pos); 920*1da177e4SLinus Torvalds } 921*1da177e4SLinus Torvalds 922*1da177e4SLinus Torvalds static void *clip_seq_start(struct seq_file *seq, loff_t *pos) 923*1da177e4SLinus Torvalds { 924*1da177e4SLinus Torvalds return neigh_seq_start(seq, pos, &clip_tbl, NEIGH_SEQ_NEIGH_ONLY); 925*1da177e4SLinus Torvalds } 926*1da177e4SLinus Torvalds 927*1da177e4SLinus Torvalds static int clip_seq_show(struct seq_file *seq, void *v) 928*1da177e4SLinus Torvalds { 929*1da177e4SLinus Torvalds static char atm_arp_banner[] = 930*1da177e4SLinus Torvalds "IPitf TypeEncp Idle IP address ATM address\n"; 931*1da177e4SLinus Torvalds 932*1da177e4SLinus Torvalds if (v == SEQ_START_TOKEN) { 933*1da177e4SLinus Torvalds seq_puts(seq, atm_arp_banner); 934*1da177e4SLinus Torvalds } else { 935*1da177e4SLinus Torvalds struct clip_seq_state *state = seq->private; 936*1da177e4SLinus Torvalds struct neighbour *n = v; 937*1da177e4SLinus Torvalds struct clip_vcc *vcc = state->vcc; 938*1da177e4SLinus Torvalds 939*1da177e4SLinus Torvalds atmarp_info(seq, n->dev, NEIGH2ENTRY(n), vcc); 940*1da177e4SLinus Torvalds } 941*1da177e4SLinus Torvalds return 0; 942*1da177e4SLinus Torvalds } 943*1da177e4SLinus Torvalds 944*1da177e4SLinus Torvalds static struct seq_operations arp_seq_ops = { 945*1da177e4SLinus Torvalds .start = clip_seq_start, 946*1da177e4SLinus Torvalds .next = neigh_seq_next, 947*1da177e4SLinus Torvalds .stop = neigh_seq_stop, 948*1da177e4SLinus Torvalds .show = clip_seq_show, 949*1da177e4SLinus Torvalds }; 950*1da177e4SLinus Torvalds 951*1da177e4SLinus Torvalds static int arp_seq_open(struct inode *inode, struct file *file) 952*1da177e4SLinus Torvalds { 953*1da177e4SLinus Torvalds struct clip_seq_state *state; 954*1da177e4SLinus Torvalds struct seq_file *seq; 955*1da177e4SLinus Torvalds int rc = -EAGAIN; 956*1da177e4SLinus Torvalds 957*1da177e4SLinus Torvalds state = kmalloc(sizeof(*state), GFP_KERNEL); 958*1da177e4SLinus Torvalds if (!state) { 959*1da177e4SLinus Torvalds rc = -ENOMEM; 960*1da177e4SLinus Torvalds goto out_kfree; 961*1da177e4SLinus Torvalds } 962*1da177e4SLinus Torvalds memset(state, 0, sizeof(*state)); 963*1da177e4SLinus Torvalds state->ns.neigh_sub_iter = clip_seq_sub_iter; 964*1da177e4SLinus Torvalds 965*1da177e4SLinus Torvalds rc = seq_open(file, &arp_seq_ops); 966*1da177e4SLinus Torvalds if (rc) 967*1da177e4SLinus Torvalds goto out_kfree; 968*1da177e4SLinus Torvalds 969*1da177e4SLinus Torvalds seq = file->private_data; 970*1da177e4SLinus Torvalds seq->private = state; 971*1da177e4SLinus Torvalds out: 972*1da177e4SLinus Torvalds return rc; 973*1da177e4SLinus Torvalds 974*1da177e4SLinus Torvalds out_kfree: 975*1da177e4SLinus Torvalds kfree(state); 976*1da177e4SLinus Torvalds goto out; 977*1da177e4SLinus Torvalds } 978*1da177e4SLinus Torvalds 979*1da177e4SLinus Torvalds static struct file_operations arp_seq_fops = { 980*1da177e4SLinus Torvalds .open = arp_seq_open, 981*1da177e4SLinus Torvalds .read = seq_read, 982*1da177e4SLinus Torvalds .llseek = seq_lseek, 983*1da177e4SLinus Torvalds .release = seq_release_private, 984*1da177e4SLinus Torvalds .owner = THIS_MODULE 985*1da177e4SLinus Torvalds }; 986*1da177e4SLinus Torvalds #endif 987*1da177e4SLinus Torvalds 988*1da177e4SLinus Torvalds static int __init atm_clip_init(void) 989*1da177e4SLinus Torvalds { 990*1da177e4SLinus Torvalds neigh_table_init(&clip_tbl); 991*1da177e4SLinus Torvalds 992*1da177e4SLinus Torvalds clip_tbl_hook = &clip_tbl; 993*1da177e4SLinus Torvalds register_atm_ioctl(&clip_ioctl_ops); 994*1da177e4SLinus Torvalds 995*1da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 996*1da177e4SLinus Torvalds { 997*1da177e4SLinus Torvalds struct proc_dir_entry *p; 998*1da177e4SLinus Torvalds 999*1da177e4SLinus Torvalds p = create_proc_entry("arp", S_IRUGO, atm_proc_root); 1000*1da177e4SLinus Torvalds if (p) 1001*1da177e4SLinus Torvalds p->proc_fops = &arp_seq_fops; 1002*1da177e4SLinus Torvalds } 1003*1da177e4SLinus Torvalds #endif 1004*1da177e4SLinus Torvalds 1005*1da177e4SLinus Torvalds return 0; 1006*1da177e4SLinus Torvalds } 1007*1da177e4SLinus Torvalds 1008*1da177e4SLinus Torvalds static void __exit atm_clip_exit(void) 1009*1da177e4SLinus Torvalds { 1010*1da177e4SLinus Torvalds struct net_device *dev, *next; 1011*1da177e4SLinus Torvalds 1012*1da177e4SLinus Torvalds remove_proc_entry("arp", atm_proc_root); 1013*1da177e4SLinus Torvalds 1014*1da177e4SLinus Torvalds deregister_atm_ioctl(&clip_ioctl_ops); 1015*1da177e4SLinus Torvalds 1016*1da177e4SLinus Torvalds /* First, stop the idle timer, so it stops banging 1017*1da177e4SLinus Torvalds * on the table. 1018*1da177e4SLinus Torvalds */ 1019*1da177e4SLinus Torvalds if (start_timer == 0) 1020*1da177e4SLinus Torvalds del_timer(&idle_timer); 1021*1da177e4SLinus Torvalds 1022*1da177e4SLinus Torvalds /* Next, purge the table, so that the device 1023*1da177e4SLinus Torvalds * unregister loop below does not hang due to 1024*1da177e4SLinus Torvalds * device references remaining in the table. 1025*1da177e4SLinus Torvalds */ 1026*1da177e4SLinus Torvalds neigh_ifdown(&clip_tbl, NULL); 1027*1da177e4SLinus Torvalds 1028*1da177e4SLinus Torvalds dev = clip_devs; 1029*1da177e4SLinus Torvalds while (dev) { 1030*1da177e4SLinus Torvalds next = PRIV(dev)->next; 1031*1da177e4SLinus Torvalds unregister_netdev(dev); 1032*1da177e4SLinus Torvalds free_netdev(dev); 1033*1da177e4SLinus Torvalds dev = next; 1034*1da177e4SLinus Torvalds } 1035*1da177e4SLinus Torvalds 1036*1da177e4SLinus Torvalds /* Now it is safe to fully shutdown whole table. */ 1037*1da177e4SLinus Torvalds neigh_table_clear(&clip_tbl); 1038*1da177e4SLinus Torvalds 1039*1da177e4SLinus Torvalds clip_tbl_hook = NULL; 1040*1da177e4SLinus Torvalds } 1041*1da177e4SLinus Torvalds 1042*1da177e4SLinus Torvalds module_init(atm_clip_init); 1043*1da177e4SLinus Torvalds module_exit(atm_clip_exit); 1044*1da177e4SLinus Torvalds 1045*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1046