diff -ur --new-file old/linux/include/linux/arequipa.h new/linux/include/linux/arequipa.h --- old/linux/include/linux/arequipa.h Tue Apr 22 23:48:08 1997 +++ new/linux/include/linux/arequipa.h Tue Apr 22 23:48:41 1997 @@ -1,6 +1,6 @@ /* arequipa.h - Arequipa interface definitions */ -/* Written 1996 by Jean-Michel Pittet and Werner Almesberger, EPFL LRC */ +/* Written 1996,1997 by Jean-Michel Pittet and Werner Almesberger, EPFL LRC */ #ifndef _LINUX_AREQUIPA_H @@ -9,12 +9,23 @@ #include +enum arequipa_msg_type { amt_invalid,amt_close,amt_sync }; + +struct arequipa_msg { + enum arequipa_msg_type type; + void *ptr; +}; + + #define AREQUIPA_PRESET _IO('a',ATMIOC_AREQUIPA) #define AREQUIPA_INCOMING _IO('a',ATMIOC_AREQUIPA+1) #define AREQUIPA_EXPECT _IO('a',ATMIOC_AREQUIPA+2) #define AREQUIPA_CLOSE _IO('a',ATMIOC_AREQUIPA+3) #define AREQUIPA_CTRL _IO('a',ATMIOC_AREQUIPA+4) #define AREQUIPA_CLS3RD _IO('a',ATMIOC_AREQUIPA+5) +#define AREQUIPA_SYNCREQ _IO('a',ATMIOC_AREQUIPA+6) +#define AREQUIPA_SYNCACK _IO('a',ATMIOC_AREQUIPA+7) +#define AREQUIPA_WORK _IO('a',ATMIOC_AREQUIPA+8) #ifdef __KERNEL__ @@ -37,9 +48,12 @@ int arequipa_expect(struct sock *upper,int on); int arequipa_incoming(struct socket *lower); int arequipa_close(struct sock *upper); +void arequipa_synchronize(void); +void arequipa_work(void); int arequipad_attach(struct atm_vcc *vcc); void arequipa_close_vcc(struct atm_vcc *vcc); + #endif /* __KERNEL__ */ diff -ur --new-file old/linux/net/atm/arequipa.c new/linux/net/atm/arequipa.c --- old/linux/net/atm/arequipa.c Tue Apr 22 23:48:08 1997 +++ new/linux/net/atm/arequipa.c Tue Apr 22 23:48:40 1997 @@ -17,6 +17,8 @@ #include #include #include +#include /* for struct wait_queue */ +#include /* for sleep_on */ #include #include #include /* cli and such */ @@ -59,6 +61,8 @@ static struct atm_vcc *aq_list = NULL; /* dangling Arequipa VCs */ static unsigned long aq_generation = 0; +static struct sk_buff_head pending; /* pending Arequipa messages */ +static atomic_t pending_inuse; static void arequipa_unuse(struct atm_vcc *vcc) @@ -88,25 +92,29 @@ */ -static void aqd_enq(struct atm_vcc *vcc) +static void aqd_enq(enum arequipa_msg_type type,void *ptr) { struct sk_buff *skb; - if (!aqd) { - printk(KERN_CRIT "aqd_enq: no Arequipa demon\n"); - return; - } - skb = alloc_skb(sizeof(vcc),GFP_ATOMIC); + if (!aqd) printk(KERN_WARNING "aqd_enq: no Arequipa demon\n"); + skb = alloc_skb(sizeof(struct arequipa_msg),GFP_ATOMIC); if (!skb) { - printk(KERN_CRIT "adq_enq: out of memory\n"); + printk(KERN_CRIT "aqd_enq: out of memory\n"); return; } skb->free = 1; - skb->len = sizeof(vcc); - *(struct atm_vcc **) skb->data = vcc; - atomic_add(skb->truesize+ATM_PDU_OVHD,&aqd->rx_inuse); - skb_queue_tail(&aqd->recvq,skb); - wake_up(&aqd->sleep); + skb->len = sizeof(struct arequipa_msg); + ((struct arequipa_msg *) skb->data)->type = type; + ((struct arequipa_msg *) skb->data)->ptr = ptr; + if (aqd) { + atomic_add(skb->truesize+ATM_PDU_OVHD,&aqd->rx_inuse); + skb_queue_tail(&aqd->recvq,skb); + wake_up(&aqd->sleep); + } + else { + atomic_add(skb->truesize+ATM_PDU_OVHD,&pending_inuse); + skb_queue_tail(&pending,skb); + } } @@ -124,7 +132,8 @@ upper->ip_route_cache = NULL; upper->arequipa = NULL; ATM_SD(lower)->upper = NULL; - if (!(ATM_SD(lower)->flags & ATM_VF_AQREL)) aqd_enq(ATM_SD(lower)); + if (!(ATM_SD(lower)->flags & ATM_VF_AQREL)) + aqd_enq(amt_close,ATM_SD(lower)); ATM_SD(lower)->flags |= ATM_VF_AQREL; restore_flags(flags); return 0; @@ -221,7 +230,7 @@ restore_flags(flags); lower->file->f_count++; /* re-process everything received between connection setup and - AREQUIPA_INCOMING*/ + AREQUIPA_INCOMING */ while ((skb = skb_dequeue(©))) atm_push_arequipa(vcc,skb); } @@ -385,21 +394,26 @@ arequipa_dev->init = arequipa_init; arequipa_rt.rt_dev = arequipa_dev; arequipa_init(arequipa_dev); + skb_queue_head_init(&pending); + pending_inuse = 0; return 0; } static void aqd_close(struct atm_vcc *vcc) { - struct sk_buff *skb; + unsigned long flags; DPRINTK("aqd_close\n"); + save_flags(flags); + cli(); aqd = NULL; /* assumed to be atomic */ - barrier(); - if (skb_peek(&vcc->recvq)) + skb_migrate(&vcc->recvq,&pending); + pending_inuse = vcc->rx_inuse; + restore_flags(flags); + if (skb_peek(&pending)) printk(KERN_CRIT "aqd_close: closing with requests " "pending\n"); - while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb,FREE_READ); } @@ -433,7 +447,11 @@ int arequipad_attach(struct atm_vcc *vcc) { + unsigned long flags; + if (aqd) return -EADDRINUSE; + save_flags(flags); + cli(); aqd = vcc; vcc->flags |= ATM_VF_READY | ATM_VF_META; /* allow replies and avoid getting closed if signaling dies */ @@ -443,10 +461,49 @@ vcc->peek = NULL; /* crash */ vcc->pop = NULL; /* crash */ vcc->push_oam = NULL; /* crash */ - /* - * Now that we have an arequipad, we should check for stale Arequipa - * connections and prune them. @@@ - */ + if (skb_peek(&pending)) { + skb_migrate(&pending,&vcc->recvq); + vcc->rx_inuse = pending_inuse; + } + restore_flags(flags); return 0; +} + + +void arequipa_synchronize(void) +{ + struct wait_queue *wait; + + init_waitqueue(&wait); + aqd_enq(amt_sync,&wait); + sleep_on(&wait); +} + + +void arequipa_work(void) +{ + struct sk_buff *skb; + struct arequipa_msg *msg; + + if (!aqd) { + printk(KERN_ERR "arequipa_work invoked but arequipad isn't " + "connected\n"); + return; + } + while ((skb = skb_dequeue(&aqd->recvq))) { + msg = (struct arequipa_msg *) skb->data; + switch (msg->type) { + case amt_close: + arequipa_close_vcc(msg->ptr); + break; + case amt_sync: + wake_up(msg->ptr); + break; + default: + printk(KERN_ERR "unrecognized Arequipa message" + " type %d\n",(int) msg->type); + } + atomic_sub(skb->truesize+ATM_PDU_OVHD,&aqd->rx_inuse); + } } diff -ur --new-file old/linux/net/atm/atmarp.c new/linux/net/atm/atmarp.c --- old/linux/net/atm/atmarp.c Tue Apr 22 23:48:08 1997 +++ new/linux/net/atm/atmarp.c Tue Apr 22 23:48:40 1997 @@ -360,7 +360,6 @@ entry = new_entry(timeout); if (!entry) return -ENOMEM; attach_entry(vcc,entry); - idle_timer_check(0); return 0; } @@ -430,6 +429,7 @@ PRIV(AE(vcc)->dev)->table = AE(vcc); restore_flags(flags); if (queued) clip_xmit(queued,route->rt_dev); + idle_timer_check(0); return 0; } diff -ur --new-file old/linux/net/atm/common.c new/linux/net/atm/common.c --- old/linux/net/atm/common.c Tue Apr 22 23:48:07 1997 +++ new/linux/net/atm/common.c Tue Apr 22 23:48:40 1997 @@ -692,6 +692,14 @@ if (!suser()) return -EPERM; arequipa_close_vcc((struct atm_vcc *) arg); return 0; + case AREQUIPA_SYNCACK: + if (!suser()) return -EPERM; + wake_up((struct wait_queue **) arg); + return 0; + case AREQUIPA_WORK: + if (!suser()) return -EPERM; + arequipa_work(); + return 0; #endif #ifdef CONFIG_ATM_LANE case ATMLEC_CTRL: diff -ur --new-file old/linux/net/atm/ipcommon.c new/linux/net/atm/ipcommon.c --- old/linux/net/atm/ipcommon.c Tue Apr 22 23:48:08 1997 +++ new/linux/net/atm/ipcommon.c Tue Apr 22 23:48:40 1997 @@ -222,8 +222,10 @@ void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to) { - struct sk_buff *prev; + struct sk_buff *skb,*prev; + for (skb = ((struct sk_buff *) from)->next; + skb != (struct sk_buff *) from; skb = skb->next) skb->list = to; prev = from->prev; from->next->prev = (struct sk_buff *) to; prev->next = (struct sk_buff *) to; diff -ur --new-file old/linux/net/ipv4/af_inet.c new/linux/net/ipv4/af_inet.c --- old/linux/net/ipv4/af_inet.c Tue Apr 22 23:48:08 1997 +++ new/linux/net/ipv4/af_inet.c Tue Apr 22 23:48:40 1997 @@ -1370,6 +1370,9 @@ return arequipa_expect(sk,arg); case AREQUIPA_CLOSE: return arequipa_close(sk); + case AREQUIPA_SYNCREQ: + arequipa_synchronize(); + return 0; #endif default: if ((cmd >= SIOCDEVPRIVATE) && .