int atm_charge(struct atm_vcc *vcc, int truesize) { atm_force_charge(vcc, truesize); if (atomic_read(&sk_atm(vcc)->sk_rmem_alloc) <= sk_atm(vcc)->sk_rcvbuf) return 1; atm_return(vcc, truesize); atomic_inc(&vcc->stats->rx_drop); return 0; }
static void sigd_put_skb(struct sk_buff *skb) { if (!sigd) { pr_debug("atmsvc: no signaling daemon\n"); kfree_skb(skb); return; } atm_force_charge(sigd, skb->truesize); skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb); sk_atm(sigd)->sk_data_ready(sk_atm(sigd)); }
static void svc_disconnect(struct atm_vcc *vcc) { DEFINE_WAIT(wait); struct sk_buff *skb; struct sock *sk = sk_atm(vcc); pr_debug("svc_disconnect %p\n",vcc); if (test_bit(ATM_VF_REGIS,&vcc->flags)) { prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_close,NULL,NULL,NULL); while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { schedule(); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); } while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { atm_return(vcc, skb->truesize); pr_debug("LISTEN REL\n"); sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0); dev_kfree_skb(skb); } clear_bit(ATM_VF_REGIS, &vcc->flags); }
static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc) { struct sock *sk = sk_atm(vcc); seq_printf(seq, "%pK ", vcc); if (!vcc->dev) seq_printf(seq, "Unassigned "); else seq_printf(seq, "%3d %3d %5d ", vcc->dev->number, vcc->vpi, vcc->vci); switch (sk->sk_family) { case AF_ATMPVC: seq_printf(seq, "PVC"); break; case AF_ATMSVC: seq_printf(seq, "SVC"); break; default: seq_printf(seq, "%3d", sk->sk_family); } seq_printf(seq, " %04lx %5d %7d/%7d %7d/%7d [%d]\n", vcc->flags, sk->sk_err, sk_wmem_alloc_get(sk), sk->sk_sndbuf, sk_rmem_alloc_get(sk), sk->sk_rcvbuf, atomic_read(&sk->sk_refcnt)); }
static void svc_disconnect(struct atm_vcc *vcc) { DEFINE_WAIT(wait); struct sk_buff *skb; struct sock *sk = sk_atm(vcc); DPRINTK("svc_disconnect %p\n",vcc); if (test_bit(ATM_VF_REGIS,&vcc->flags)) { prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_close,NULL,NULL,NULL); while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { schedule(); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); } /* beware - socket is still in use by atmsigd until the last as_indicate has been answered */ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { atm_return(vcc, skb->truesize); DPRINTK("LISTEN REL\n"); sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0); dev_kfree_skb(skb); } clear_bit(ATM_VF_REGIS, &vcc->flags); /* ... may retry later */ }
static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) { struct sock *sk; struct k_message *purge_msg; struct sk_buff *skb; dprintk("mpoa: purge_egress_shortcut: entering\n"); if (vcc == NULL) { printk("mpoa: purge_egress_shortcut: vcc == NULL\n"); return; } skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); if (skb == NULL) { printk("mpoa: purge_egress_shortcut: out of memory\n"); return; } skb_put(skb, sizeof(struct k_message)); memset(skb->data, 0, sizeof(struct k_message)); purge_msg = (struct k_message *)skb->data; purge_msg->type = DATA_PLANE_PURGE; if (entry != NULL) purge_msg->content.eg_info = entry->ctrl_info; atm_force_charge(vcc, skb->truesize); sk = sk_atm(vcc); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); dprintk("mpoa: purge_egress_shortcut: exiting:\n"); return; }
static void mpoad_close(struct atm_vcc *vcc) { struct mpoa_client *mpc; struct sk_buff *skb; mpc = find_mpc_by_vcc(vcc); if (mpc == NULL) { pr_info("did not find MPC\n"); return; } if (!mpc->mpoad_vcc) { pr_info("close for non-present mpoad\n"); return; } mpc->mpoad_vcc = NULL; if (mpc->dev) { struct lec_priv *priv = netdev_priv(mpc->dev); priv->lane2_ops->associate_indicator = NULL; stop_mpc(mpc); dev_put(mpc->dev); } mpc->in_ops->destroy_cache(mpc); mpc->eg_ops->destroy_cache(mpc); while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) { atm_return(vcc, skb->truesize); kfree_skb(skb); } pr_info("(%s) going down\n", (mpc->dev) ? mpc->dev->name : "<unknown>"); module_put(THIS_MODULE); }
static void purge_vcc(struct atm_vcc *vcc) { if (sk_atm(vcc)->sk_family == PF_ATMSVC && !test_bit(ATM_VF_META, &vcc->flags)) { set_bit(ATM_VF_RELEASED, &vcc->flags); clear_bit(ATM_VF_REGIS, &vcc->flags); vcc_release_async(vcc, -EUNATCH); } }
static void atm_push_raw(struct atm_vcc *vcc, struct sk_buff *skb) { if (skb) { struct sock *sk = sk_atm(vcc); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); } }
static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb) { struct sock *sk = sk_atm(vcc); pr_debug("(%d) %d -= %d\n", vcc->vci, sk_wmem_alloc_get(sk), skb->truesize); atomic_sub(skb->truesize, &sk->sk_wmem_alloc); dev_kfree_skb_any(skb); sk->sk_write_space(sk); }
void vcc_release_async(struct atm_vcc *vcc, int reply) { struct sock *sk = sk_atm(vcc); set_bit(ATM_VF_CLOSE, &vcc->flags); sk->sk_shutdown |= RCV_SHUTDOWN; sk->sk_err = -reply; clear_bit(ATM_VF_WAITING, &vcc->flags); sk->sk_state_change(sk); }
static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb) { struct mpoa_client *mpc = find_mpc_by_vcc(vcc); struct k_message *mesg = (struct k_message *)skb->data; atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); if (mpc == NULL) { pr_info("no mpc found\n"); return 0; } dprintk("(%s)", mpc->dev ? mpc->dev->name : "<unknown>"); switch (mesg->type) { case MPOA_RES_REPLY_RCVD: dprintk_cont("mpoa_res_reply_rcvd\n"); MPOA_res_reply_rcvd(mesg, mpc); break; case MPOA_TRIGGER_RCVD: dprintk_cont("mpoa_trigger_rcvd\n"); MPOA_trigger_rcvd(mesg, mpc); break; case INGRESS_PURGE_RCVD: dprintk_cont("nhrp_purge_rcvd\n"); ingress_purge_rcvd(mesg, mpc); break; case EGRESS_PURGE_RCVD: dprintk_cont("egress_purge_reply_rcvd\n"); egress_purge_rcvd(mesg, mpc); break; case MPS_DEATH: dprintk_cont("mps_death\n"); mps_death(mesg, mpc); break; case CACHE_IMPOS_RCVD: dprintk_cont("cache_impos_rcvd\n"); MPOA_cache_impos_rcvd(mesg, mpc); break; case SET_MPC_CTRL_ADDR: dprintk_cont("set_mpc_ctrl_addr\n"); set_mpc_ctrl_addr_rcvd(mesg, mpc); break; case SET_MPS_MAC_ADDR: dprintk_cont("set_mps_mac_addr\n"); set_mps_mac_addr_rcvd(mesg, mpc); break; case CLEAN_UP_AND_EXIT: dprintk_cont("clean_up_and_exit\n"); clean_up(mesg, mpc, DIE); break; case RELOAD: dprintk_cont("reload\n"); clean_up(mesg, mpc, RELOAD); break; case SET_MPC_PA
static void sigd_close(struct atm_vcc *vcc) { struct sock *s; int i; pr_debug("\n"); sigd = NULL; if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) pr_err("closing with requests pending\n"); skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); read_lock(&vcc_sklist_lock); for (i = 0; i < VCC_HTABLE_SIZE; ++i) { struct hlist_head *head = &vcc_hash[i]; sk_for_each(s, head) { vcc = atm_sk(s); purge_vcc(vcc); } }
static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) { struct pppoatm_vcc *pvcc = chan_to_pvcc(chan); ATM_SKB(skb)->vcc = pvcc->atmvcc; pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) (void) skb_pull(skb, 1); switch (pvcc->encaps) { /* LLC encapsulation needed */ case e_llc: if (skb_headroom(skb) < LLC_LEN) { struct sk_buff *n; n = skb_realloc_headroom(skb, LLC_LEN); if (n != NULL && !atm_may_send(pvcc->atmvcc, n->truesize)) { kfree_skb(n); goto nospace; } kfree_skb(skb); skb = n; if (skb == NULL) return DROP_PACKET; } else if (!atm_may_send(pvcc->atmvcc, skb->truesize)) goto nospace; memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN); break; case e_vc: if (!atm_may_send(pvcc->atmvcc, skb->truesize)) goto nospace; break; case e_autodetect: pr_debug("Trying to send without setting encaps!\n"); kfree_skb(skb); return 1; } atomic_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc); ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) ? DROP_PACKET : 1; nospace: /* * We don't have space to send this SKB now, but we might have * already applied SC_COMP_PROT compression, so may need to undo */ if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 && skb->data[-1] == '\0') (void) skb_push(skb, 1); return 0; }
int sigd_attach(struct atm_vcc *vcc) { if (sigd) return -EADDRINUSE; DPRINTK("sigd_attach\n"); sigd = vcc; vcc->dev = &sigd_dev; vcc_insert_socket(sk_atm(vcc)); set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_READY,&vcc->flags); #ifdef WAIT_FOR_DEMON wake_up(&sigd_sleep); #endif return 0; }
static void sigd_put_skb(struct sk_buff *skb) { #ifdef WAIT_FOR_DEMON DECLARE_WAITQUEUE(wait,current); add_wait_queue(&sigd_sleep,&wait); while (!sigd) { set_current_state(TASK_UNINTERRUPTIBLE); pr_debug("atmsvc: waiting for signaling demon...\n"); schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&sigd_sleep,&wait); #else if (!sigd) { pr_debug("atmsvc: no signaling demon\n"); kfree_skb(skb); return; } #endif atm_force_charge(sigd,skb->truesize); skb_queue_tail(&sk_atm(sigd)->sk_receive_queue,skb); sk_atm(sigd)->sk_data_ready(sk_atm(sigd), skb->len); }
static void sigd_close(struct atm_vcc *vcc) { struct hlist_node *node; struct sock *s; int i; DPRINTK("sigd_close\n"); sigd = NULL; if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) printk(KERN_ERR "sigd_close: closing with requests pending\n"); skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); read_lock(&vcc_sklist_lock); for(i = 0; i < VCC_HTABLE_SIZE; ++i) { struct hlist_head *head = &vcc_hash[i]; sk_for_each(s, node, head) { struct atm_vcc *vcc = atm_sk(s); purge_vcc(vcc); } } read_unlock(&vcc_sklist_lock); }
static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size) { struct sk_buff *skb; struct sock *sk = sk_atm(vcc); if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) { pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n", sk_wmem_alloc_get(sk), size, sk->sk_sndbuf); return NULL; } while (!(skb = alloc_skb(size, GFP_KERNEL))) schedule(); pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize); atomic_add(skb->truesize, &sk->sk_wmem_alloc); return skb; }
int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) { struct sock *sk = sk_atm(vcc); DEFINE_WAIT(wait); set_bit(ATM_VF_WAITING, &vcc->flags); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0); while (test_bit(ATM_VF_WAITING, &vcc->flags) && !test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) { schedule(); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); if (!sigd) return -EUNATCH; return -sk->sk_err; }
struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc, int pdu_size, gfp_t gfp_flags) { struct sock *sk = sk_atm(vcc); int guess = atm_guess_pdu2truesize(pdu_size); atm_force_charge(vcc, guess); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { struct sk_buff *skb = alloc_skb(pdu_size, gfp_flags); if (skb) { atomic_add(skb->truesize-guess, &sk->sk_rmem_alloc); return skb; } } atm_return(vcc, guess); atomic_inc(&vcc->stats->rx_drop); return NULL; }
static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip) { struct sock *sk; struct atmarp_ctrl *ctrl; struct sk_buff *skb; DPRINTK("to_atmarpd(%d)\n",type); if (!atmarpd) return -EUNATCH; skb = alloc_skb(sizeof(struct atmarp_ctrl),GFP_ATOMIC); if (!skb) return -ENOMEM; ctrl = (struct atmarp_ctrl *) skb_put(skb,sizeof(struct atmarp_ctrl)); ctrl->type = type; ctrl->itf_num = itf; ctrl->ip = ip; atm_force_charge(atmarpd,skb->truesize); sk = sk_atm(atmarpd); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); return 0; }
static 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; set_bit(ATM_VF_IS_CLIP, &vcc->flags); 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(&sk_atm(vcc)->sk_receive_queue, ©); /* re-process everything received between connection setup and MKIP */ while ((skb = skb_dequeue(©)) != NULL) 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; }
/* Remember that this function may not do things that sleep */ int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc) { struct sk_buff *skb; struct sock *sk; if (mpc == NULL || !mpc->mpoad_vcc) { printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg->type); return -ENXIO; } skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); if (skb == NULL) return -ENOMEM; skb_put(skb, sizeof(struct k_message)); memcpy(skb->data, mesg, sizeof(struct k_message)); atm_force_charge(mpc->mpoad_vcc, skb->truesize); sk = sk_atm(mpc->mpoad_vcc); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); return 0; }
static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) { struct mpoa_client *mpc; struct lec_priv *priv; int err; if (mpcs == NULL) { init_timer(&mpc_timer); mpc_timer_refresh(); /* This lets us now how our LECs are doing */ err = register_netdevice_notifier(&mpoa_notifier); if (err < 0) { del_timer(&mpc_timer); return err; } } mpc = find_mpc_by_itfnum(arg); if (mpc == NULL) { dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg); mpc = alloc_mpc(); if (mpc == NULL) return -ENOMEM; mpc->dev_num = arg; mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */ } if (mpc->mpoad_vcc) { printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg); return -EADDRINUSE; } if (mpc->dev) { /* check if the lec is LANE2 capable */ priv = (struct lec_priv *)mpc->dev->priv; if (priv->lane_version < 2) { dev_put(mpc->dev); mpc->dev = NULL; } else priv->lane2_ops->associate_indicator = lane2_assoc_ind; } mpc->mpoad_vcc = vcc; vcc->dev = &mpc_dev; vcc_insert_socket(sk_atm(vcc)); set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_READY,&vcc->flags); if (mpc->dev) { char empty[ATM_ESA_LEN]; memset(empty, 0, ATM_ESA_LEN); start_mpc(mpc, mpc->dev); /* set address if mpcd e.g. gets killed and restarted. * If we do not do it now we have to wait for the next LE_ARP */ if ( memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0 ) send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc); } __module_get(THIS_MODULE); return arg; }
static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) { struct net_device *dev = (struct net_device *)vcc->proto_data; struct sk_buff *new_skb; eg_cache_entry *eg; struct mpoa_client *mpc; uint32_t tag; char *tmp; ddprintk("mpoa: (%s) mpc_push:\n", dev->name); if (skb == NULL) { dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", dev->name); mpc_vcc_close(vcc, dev); return; } skb->dev = dev; if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) { struct sock *sk = sk_atm(vcc); dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name); /* Pass control packets to daemon */ skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); return; } /* data coming over the shortcut */ atm_return(vcc, skb->truesize); mpc = find_mpc_by_lec(dev); if (mpc == NULL) { printk("mpoa: (%s) mpc_push: unknown MPC\n", dev->name); return; } if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */ ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", dev->name); } else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */ printk("mpoa: (%s) mpc_push: non-tagged data packet arrived\n", dev->name); printk(" mpc_push: non-tagged data unsupported, purging\n"); dev_kfree_skb_any(skb); return; } else { printk("mpoa: (%s) mpc_push: garbage arrived, purging\n", dev->name); dev_kfree_skb_any(skb); return; } tmp = skb->data + sizeof(struct llc_snap_hdr); tag = *(uint32_t *)tmp; eg = mpc->eg_ops->get_by_tag(tag, mpc); if (eg == NULL) { printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n", dev->name,tag); purge_egress_shortcut(vcc, NULL); dev_kfree_skb_any(skb); return; } /* * See if ingress MPC is using shortcut we opened as a return channel. * This means we have a bi-directional vcc opened by us. */ if (eg->shortcut == NULL) { eg->shortcut = vcc; printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev->name); } skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */ new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */ dev_kfree_skb_any(skb); if (new_skb == NULL){ mpc->eg_ops->put(eg); return; } skb_push(new_skb, eg->ctrl_info.DH_length); /* add MAC header */ memcpy(new_skb->data, eg->ctrl_info.DLL_header, eg->ctrl_info.DH_length); new_skb->protocol = eth_type_trans(new_skb, dev); new_skb->nh.raw = new_skb->data; eg->latest_ip_addr = new_skb->nh.iph->saddr; eg->packets_rcvd++; mpc->eg_ops->put(eg); memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(new_skb); return; }
static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) { in_cache_entry *entry; struct iphdr *iph; char *buff; uint32_t ipaddr = 0; static struct { struct llc_snap_hdr hdr; uint32_t tag; } tagged_llc_snap_hdr = { {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}}, 0 }; buff = skb->data + mpc->dev->hard_header_len; iph = (struct iphdr *)buff; ipaddr = iph->daddr; ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr); entry = mpc->in_ops->get(ipaddr, mpc); if (entry == NULL) { entry = mpc->in_ops->add_entry(ipaddr, mpc); if (entry != NULL) mpc->in_ops->put(entry); return 1; } if (mpc->in_ops->cache_hit(entry, mpc) != OPEN){ /* threshold not exceeded or VCC not ready */ ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", mpc->dev->name); mpc->in_ops->put(entry); return 1; } ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", mpc->dev->name); /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */ if (iph->ttl <= 1) { ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl); mpc->in_ops->put(entry); return 1; } iph->ttl--; iph->check = 0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); if (entry->ctrl_info.tag != 0) { ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag); tagged_llc_snap_hdr.tag = entry->ctrl_info.tag; skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ skb_push(skb, sizeof(tagged_llc_snap_hdr)); /* add LLC/SNAP header */ memcpy(skb->data, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr)); } else { skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ skb_push(skb, sizeof(struct llc_snap_hdr)); /* add LLC/SNAP header + tag */ memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)); } atomic_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc); ATM_SKB(skb)->atm_options = entry->shortcut->atm_options; entry->shortcut->send(entry->shortcut, skb); entry->packets_fwded++; mpc->in_ops->put(entry); return 0; }
static int clip_mkip(struct atm_vcc *vcc, int timeout) { struct clip_vcc *clip_vcc; struct sk_buff *skb; struct sk_buff_head *rq; unsigned long flags; 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; set_bit(ATM_VF_IS_CLIP, &vcc->flags); 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; rq = &sk_atm(vcc)->sk_receive_queue; spin_lock_irqsave(&rq->lock, flags); if (skb_queue_empty(rq)) { skb = NULL; } else { /* NULL terminate the list. */ rq->prev->next = NULL; skb = rq->next; } rq->prev = rq->next = (struct sk_buff *)rq; rq->qlen = 0; spin_unlock_irqrestore(&rq->lock, flags); /* re-process everything received between connection setup and MKIP */ while (skb) { struct sk_buff *next = skb->next; skb->next = skb->prev = NULL; if (!clip_devs) { atm_return(vcc, skb->truesize); kfree_skb(skb); } else { unsigned int len = skb->len; skb_get(skb); clip_push(vcc, skb); PRIV(skb->dev)->stats.rx_packets--; PRIV(skb->dev)->stats.rx_bytes -= len; kfree_skb(skb); } skb = next; } return 0; }
static int svc_accept(struct socket *sock,struct socket *newsock,int flags) { struct sock *sk = sock->sk; struct sk_buff *skb; struct atmsvc_msg *msg; struct atm_vcc *old_vcc = ATM_SD(sock); struct atm_vcc *new_vcc; int error; lock_sock(sk); error = svc_create(newsock,0); if (error) goto out; new_vcc = ATM_SD(newsock); DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc); while (1) { DEFINE_WAIT(wait); prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); while (!(skb = skb_dequeue(&sk->sk_receive_queue)) && sigd) { if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break; if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) { error = -sk->sk_err; break; } if (flags & O_NONBLOCK) { error = -EAGAIN; break; } release_sock(sk); schedule(); lock_sock(sk); if (signal_pending(current)) { error = -ERESTARTSYS; break; } prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); } finish_wait(sk->sk_sleep, &wait); if (error) goto out; if (!skb) { error = -EUNATCH; goto out; } msg = (struct atmsvc_msg *) skb->data; new_vcc->qos = msg->qos; set_bit(ATM_VF_HASQOS,&new_vcc->flags); new_vcc->remote = msg->svc; new_vcc->local = msg->local; new_vcc->sap = msg->sap; error = vcc_connect(newsock, msg->pvc.sap_addr.itf, msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci); dev_kfree_skb(skb); sk->sk_ack_backlog--; if (error) { sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL, &old_vcc->qos,error); error = error == -EAGAIN ? -EBUSY : error; goto out; } /* wait should be short, so we ignore the non-blocking flag */ set_bit(ATM_VF_WAITING, &new_vcc->flags); prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); while (test_bit(ATM_VF_WAITING, &new_vcc->flags) && sigd) { release_sock(sk); schedule(); lock_sock(sk); prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); } finish_wait(sk_atm(new_vcc)->sk_sleep, &wait); if (!sigd) { error = -EUNATCH; goto out; } if (!sk_atm(new_vcc)->sk_err) break; if (sk_atm(new_vcc)->sk_err != ERESTARTSYS) { error = -sk_atm(new_vcc)->sk_err; goto out; } } newsock->state = SS_CONNECTED; out: release_sock(sk); return error; }
static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev) { struct clip_priv *clip_priv = PRIV(dev); struct atmarp_entry *entry; 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, &sk_atm(vcc)->sk_wmem_alloc); 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 int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) { struct atmsvc_msg *msg; struct atm_vcc *session_vcc; struct sock *sk; msg = (struct atmsvc_msg *) skb->data; atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type, (unsigned long) msg->vcc); vcc = *(struct atm_vcc **) &msg->vcc; sk = sk_atm(vcc); switch (msg->type) { case as_okay: sk->sk_err = -msg->reply; clear_bit(ATM_VF_WAITING, &vcc->flags); if (!*vcc->local.sas_addr.prv && !*vcc->local.sas_addr.pub) { vcc->local.sas_family = AF_ATMSVC; memcpy(vcc->local.sas_addr.prv, msg->local.sas_addr.prv,ATM_ESA_LEN); memcpy(vcc->local.sas_addr.pub, msg->local.sas_addr.pub,ATM_E164_LEN+1); } session_vcc = vcc->session ? vcc->session : vcc; if (session_vcc->vpi || session_vcc->vci) break; session_vcc->itf = msg->pvc.sap_addr.itf; session_vcc->vpi = msg->pvc.sap_addr.vpi; session_vcc->vci = msg->pvc.sap_addr.vci; if (session_vcc->vpi || session_vcc->vci) session_vcc->qos = msg->qos; break; case as_error: clear_bit(ATM_VF_REGIS,&vcc->flags); clear_bit(ATM_VF_READY,&vcc->flags); sk->sk_err = -msg->reply; clear_bit(ATM_VF_WAITING, &vcc->flags); break; case as_indicate: vcc = *(struct atm_vcc **) &msg->listen_vcc; sk = sk_atm(vcc); DPRINTK("as_indicate!!!\n"); lock_sock(sk); if (sk_acceptq_is_full(sk)) { sigd_enq(NULL,as_reject,vcc,NULL,NULL); dev_kfree_skb(skb); goto as_indicate_complete; } sk->sk_ack_backlog++; skb_queue_tail(&sk->sk_receive_queue, skb); DPRINTK("waking sk->sk_sleep 0x%p\n", sk->sk_sleep); sk->sk_state_change(sk); as_indicate_complete: release_sock(sk); return 0; case as_close: set_bit(ATM_VF_RELEASED,&vcc->flags); vcc_release_async(vcc, msg->reply); goto out; case as_modify: modify_qos(vcc,msg); break; case as_addparty: case as_dropparty: sk->sk_err_soft = msg->reply; /* < 0 failure, otherwise ep_ref */ clear_bit(ATM_VF_WAITING, &vcc->flags); break; default: printk(KERN_ALERT "sigd_send: bad message type %d\n", (int) msg->type); return -EINVAL; } sk->sk_state_change(sk); out: dev_kfree_skb(skb); return 0; }