OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [decnet/] [dn_nsp_out.c] - Diff between revs 1275 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1275 Rev 1765
 
 
/*
/*
 * DECnet       An implementation of the DECnet protocol suite for the LINUX
 * DECnet       An implementation of the DECnet protocol suite for the LINUX
 *              operating system.  DECnet is implemented using the  BSD Socket
 *              operating system.  DECnet is implemented using the  BSD Socket
 *              interface as the means of communication with the user level.
 *              interface as the means of communication with the user level.
 *
 *
 *              DECnet Network Services Protocol (Output)
 *              DECnet Network Services Protocol (Output)
 *
 *
 * Author:      Eduardo Marcelo Serrat <emserrat@geocities.com>
 * Author:      Eduardo Marcelo Serrat <emserrat@geocities.com>
 *
 *
 * Changes:
 * Changes:
 *
 *
 *    Steve Whitehouse:  Split into dn_nsp_in.c and dn_nsp_out.c from
 *    Steve Whitehouse:  Split into dn_nsp_in.c and dn_nsp_out.c from
 *                       original dn_nsp.c.
 *                       original dn_nsp.c.
 *    Steve Whitehouse:  Updated to work with my new routing architecture.
 *    Steve Whitehouse:  Updated to work with my new routing architecture.
 *    Steve Whitehouse:  Added changes from Eduardo Serrat's patches.
 *    Steve Whitehouse:  Added changes from Eduardo Serrat's patches.
 *    Steve Whitehouse:  Now conninits have the "return" bit set.
 *    Steve Whitehouse:  Now conninits have the "return" bit set.
 *    Steve Whitehouse:  Fixes to check alloc'd skbs are non NULL!
 *    Steve Whitehouse:  Fixes to check alloc'd skbs are non NULL!
 *                       Moved output state machine into one function
 *                       Moved output state machine into one function
 *    Steve Whitehouse:  New output state machine
 *    Steve Whitehouse:  New output state machine
 *         Paul Koning:  Connect Confirm message fix.
 *         Paul Koning:  Connect Confirm message fix.
 *      Eduardo Serrat:  Fix to stop dn_nsp_do_disc() sending malformed packets.
 *      Eduardo Serrat:  Fix to stop dn_nsp_do_disc() sending malformed packets.
 *    Steve Whitehouse:  dn_nsp_output() and friends needed a spring clean
 *    Steve Whitehouse:  dn_nsp_output() and friends needed a spring clean
 */
 */
 
 
/******************************************************************************
/******************************************************************************
    (c) 1995-1998 E.M. Serrat           emserrat@geocities.com
    (c) 1995-1998 E.M. Serrat           emserrat@geocities.com
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    the Free Software Foundation; either version 2 of the License, or
    any later version.
    any later version.
 
 
    This program is distributed in the hope that it will be useful,
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    GNU General Public License for more details.
*******************************************************************************/
*******************************************************************************/
 
 
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <linux/inet.h>
#include <linux/inet.h>
#include <linux/route.h>
#include <linux/route.h>
#include <net/sock.h>
#include <net/sock.h>
#include <asm/segment.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/termios.h>      
#include <linux/termios.h>      
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/poll.h>
#include <linux/if_packet.h>
#include <linux/if_packet.h>
#include <net/neighbour.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/dst.h>
#include <net/dn_nsp.h>
#include <net/dn_nsp.h>
#include <net/dn_dev.h>
#include <net/dn_dev.h>
#include <net/dn_route.h>
#include <net/dn_route.h>
 
 
 
 
static int nsp_backoff[NSP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
static int nsp_backoff[NSP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
 
 
/*
/*
 * If sk == NULL, then we assume that we are supposed to be making
 * If sk == NULL, then we assume that we are supposed to be making
 * a routing layer skb. If sk != NULL, then we are supposed to be
 * a routing layer skb. If sk != NULL, then we are supposed to be
 * creating an skb for the NSP layer.
 * creating an skb for the NSP layer.
 *
 *
 * The eventual aim is for each socket to have a cached header size
 * The eventual aim is for each socket to have a cached header size
 * for its outgoing packets, and to set hdr from this when sk != NULL.
 * for its outgoing packets, and to set hdr from this when sk != NULL.
 */
 */
struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri)
struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri)
{
{
        struct sk_buff *skb;
        struct sk_buff *skb;
        int hdr = 64;
        int hdr = 64;
 
 
        if ((skb = alloc_skb(size + hdr, pri)) == NULL)
        if ((skb = alloc_skb(size + hdr, pri)) == NULL)
                return NULL;
                return NULL;
 
 
        skb->protocol = __constant_htons(ETH_P_DNA_RT);
        skb->protocol = __constant_htons(ETH_P_DNA_RT);
        skb->pkt_type = PACKET_OUTGOING;
        skb->pkt_type = PACKET_OUTGOING;
 
 
        if (sk)
        if (sk)
                skb_set_owner_w(skb, sk);
                skb_set_owner_w(skb, sk);
 
 
        skb_reserve(skb, hdr);
        skb_reserve(skb, hdr);
 
 
        return skb;
        return skb;
}
}
 
 
/*
/*
 * Wrapper for the above, for allocs of data skbs. We try and get the
 * Wrapper for the above, for allocs of data skbs. We try and get the
 * whole size thats been asked for (plus 11 bytes of header). If this
 * whole size thats been asked for (plus 11 bytes of header). If this
 * fails, then we try for any size over 16 bytes for SOCK_STREAMS.
 * fails, then we try for any size over 16 bytes for SOCK_STREAMS.
 */
 */
struct sk_buff *dn_alloc_send_skb(struct sock *sk, int *size, int noblock, int *err)
struct sk_buff *dn_alloc_send_skb(struct sock *sk, int *size, int noblock, int *err)
{
{
        int space;
        int space;
        int len;
        int len;
        struct sk_buff *skb = NULL;
        struct sk_buff *skb = NULL;
 
 
        *err = 0;
        *err = 0;
 
 
        while(skb == NULL) {
        while(skb == NULL) {
                if (signal_pending(current)) {
                if (signal_pending(current)) {
                        *err = ERESTARTSYS;
                        *err = ERESTARTSYS;
                        break;
                        break;
                }
                }
 
 
                if (sk->shutdown & SEND_SHUTDOWN) {
                if (sk->shutdown & SEND_SHUTDOWN) {
                        *err = EINVAL;
                        *err = EINVAL;
                        break;
                        break;
                }
                }
 
 
                if (sk->err)
                if (sk->err)
                        break;
                        break;
 
 
                len = *size + 11;
                len = *size + 11;
                space = sk->sndbuf - atomic_read(&sk->wmem_alloc);
                space = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 
 
                if (space < len) {
                if (space < len) {
                        if ((sk->socket->type == SOCK_STREAM) && (space >= (16 + 11)))
                        if ((sk->socket->type == SOCK_STREAM) && (space >= (16 + 11)))
                                len = space;
                                len = space;
                }
                }
 
 
                if (space < len) {
                if (space < len) {
                        set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
                        set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
                        if (noblock) {
                        if (noblock) {
                                *err = EWOULDBLOCK;
                                *err = EWOULDBLOCK;
                                break;
                                break;
                        }
                        }
 
 
                        clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
                        clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
                        SOCK_SLEEP_PRE(sk)
                        SOCK_SLEEP_PRE(sk)
 
 
                        if ((sk->sndbuf - atomic_read(&sk->wmem_alloc)) < len)
                        if ((sk->sndbuf - atomic_read(&sk->wmem_alloc)) < len)
                                schedule();
                                schedule();
 
 
                        SOCK_SLEEP_POST(sk)
                        SOCK_SLEEP_POST(sk)
                        continue;
                        continue;
                }
                }
 
 
                if ((skb = dn_alloc_skb(sk, len, sk->allocation)) == NULL)
                if ((skb = dn_alloc_skb(sk, len, sk->allocation)) == NULL)
                        continue;
                        continue;
 
 
                *size = len - 11;
                *size = len - 11;
        }
        }
 
 
        return skb;
        return skb;
}
}
 
 
/*
/*
 * Calculate persist timer based upon the smoothed round
 * Calculate persist timer based upon the smoothed round
 * trip time and the variance. Backoff according to the
 * trip time and the variance. Backoff according to the
 * nsp_backoff[] array.
 * nsp_backoff[] array.
 */
 */
unsigned long dn_nsp_persist(struct sock *sk)
unsigned long dn_nsp_persist(struct sock *sk)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
 
 
        unsigned long t = ((scp->nsp_srtt >> 2) + scp->nsp_rttvar) >> 1;
        unsigned long t = ((scp->nsp_srtt >> 2) + scp->nsp_rttvar) >> 1;
 
 
        t *= nsp_backoff[scp->nsp_rxtshift];
        t *= nsp_backoff[scp->nsp_rxtshift];
 
 
        if (t < HZ) t = HZ;
        if (t < HZ) t = HZ;
        if (t > (600*HZ)) t = (600*HZ);
        if (t > (600*HZ)) t = (600*HZ);
 
 
        if (scp->nsp_rxtshift < NSP_MAXRXTSHIFT)
        if (scp->nsp_rxtshift < NSP_MAXRXTSHIFT)
                scp->nsp_rxtshift++;
                scp->nsp_rxtshift++;
 
 
        /* printk(KERN_DEBUG "rxtshift %lu, t=%lu\n", scp->nsp_rxtshift, t); */
        /* printk(KERN_DEBUG "rxtshift %lu, t=%lu\n", scp->nsp_rxtshift, t); */
 
 
        return t;
        return t;
}
}
 
 
/*
/*
 * This is called each time we get an estimate for the rtt
 * This is called each time we get an estimate for the rtt
 * on the link.
 * on the link.
 */
 */
static void dn_nsp_rtt(struct sock *sk, long rtt)
static void dn_nsp_rtt(struct sock *sk, long rtt)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        long srtt = (long)scp->nsp_srtt;
        long srtt = (long)scp->nsp_srtt;
        long rttvar = (long)scp->nsp_rttvar;
        long rttvar = (long)scp->nsp_rttvar;
        long delta;
        long delta;
 
 
        /*
        /*
         * If the jiffies clock flips over in the middle of timestamp
         * If the jiffies clock flips over in the middle of timestamp
         * gathering this value might turn out negative, so we make sure
         * gathering this value might turn out negative, so we make sure
         * that is it always positive here.
         * that is it always positive here.
         */
         */
        if (rtt < 0)
        if (rtt < 0)
                rtt = -rtt;
                rtt = -rtt;
        /*
        /*
         * Add new rtt to smoothed average
         * Add new rtt to smoothed average
         */
         */
        delta = ((rtt << 3) - srtt);
        delta = ((rtt << 3) - srtt);
        srtt += (delta >> 3);
        srtt += (delta >> 3);
        if (srtt >= 1)
        if (srtt >= 1)
                scp->nsp_srtt = (unsigned long)srtt;
                scp->nsp_srtt = (unsigned long)srtt;
        else
        else
                scp->nsp_srtt = 1;
                scp->nsp_srtt = 1;
 
 
        /*
        /*
         * Add new rtt varience to smoothed varience
         * Add new rtt varience to smoothed varience
         */
         */
        delta >>= 1;
        delta >>= 1;
        rttvar += ((((delta>0)?(delta):(-delta)) - rttvar) >> 2);
        rttvar += ((((delta>0)?(delta):(-delta)) - rttvar) >> 2);
        if (rttvar >= 1)
        if (rttvar >= 1)
                scp->nsp_rttvar = (unsigned long)rttvar;
                scp->nsp_rttvar = (unsigned long)rttvar;
        else
        else
                scp->nsp_rttvar = 1;
                scp->nsp_rttvar = 1;
 
 
        /* printk(KERN_DEBUG "srtt=%lu rttvar=%lu\n", scp->nsp_srtt, scp->nsp_rttvar); */
        /* printk(KERN_DEBUG "srtt=%lu rttvar=%lu\n", scp->nsp_srtt, scp->nsp_rttvar); */
}
}
 
 
/**
/**
 * dn_nsp_clone_and_send - Send a data packet by cloning it
 * dn_nsp_clone_and_send - Send a data packet by cloning it
 * @skb: The packet to clone and transmit
 * @skb: The packet to clone and transmit
 * @gfp: memory allocation flag
 * @gfp: memory allocation flag
 *
 *
 * Clone a queued data or other data packet and transmit it.
 * Clone a queued data or other data packet and transmit it.
 *
 *
 * Returns: The number of times the packet has been sent previously
 * Returns: The number of times the packet has been sent previously
 */
 */
static inline unsigned dn_nsp_clone_and_send(struct sk_buff *skb, int gfp)
static inline unsigned dn_nsp_clone_and_send(struct sk_buff *skb, int gfp)
{
{
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        struct sk_buff *skb2;
        struct sk_buff *skb2;
        int ret = 0;
        int ret = 0;
 
 
        if ((skb2 = skb_clone(skb, gfp)) != NULL) {
        if ((skb2 = skb_clone(skb, gfp)) != NULL) {
                ret = cb->xmit_count;
                ret = cb->xmit_count;
                cb->xmit_count++;
                cb->xmit_count++;
                cb->stamp = jiffies;
                cb->stamp = jiffies;
                skb2->sk = skb->sk;
                skb2->sk = skb->sk;
                dn_nsp_send(skb2);
                dn_nsp_send(skb2);
        }
        }
 
 
        return ret;
        return ret;
}
}
 
 
/**
/**
 * dn_nsp_output - Try and send something from socket queues
 * dn_nsp_output - Try and send something from socket queues
 * @sk: The socket whose queues are to be investigated
 * @sk: The socket whose queues are to be investigated
 * @gfp: The memory allocation flags
 * @gfp: The memory allocation flags
 *
 *
 * Try and send the packet on the end of the data and other data queues.
 * Try and send the packet on the end of the data and other data queues.
 * Other data gets priority over data, and if we retransmit a packet we
 * Other data gets priority over data, and if we retransmit a packet we
 * reduce the window by dividing it in two.
 * reduce the window by dividing it in two.
 *
 *
 */
 */
void dn_nsp_output(struct sock *sk)
void dn_nsp_output(struct sock *sk)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        struct sk_buff *skb;
        struct sk_buff *skb;
        unsigned reduce_win = 0;
        unsigned reduce_win = 0;
 
 
        /*
        /*
         * First we check for otherdata/linkservice messages
         * First we check for otherdata/linkservice messages
         */
         */
        if ((skb = skb_peek(&scp->other_xmit_queue)) != NULL)
        if ((skb = skb_peek(&scp->other_xmit_queue)) != NULL)
                reduce_win = dn_nsp_clone_and_send(skb, GFP_ATOMIC);
                reduce_win = dn_nsp_clone_and_send(skb, GFP_ATOMIC);
 
 
        /*
        /*
         * If we may not send any data, we don't.
         * If we may not send any data, we don't.
         * If we are still trying to get some other data down the
         * If we are still trying to get some other data down the
         * channel, we don't try and send any data.
         * channel, we don't try and send any data.
         */
         */
        if (reduce_win || (scp->flowrem_sw != DN_SEND))
        if (reduce_win || (scp->flowrem_sw != DN_SEND))
                goto recalc_window;
                goto recalc_window;
 
 
        if ((skb = skb_peek(&scp->data_xmit_queue)) != NULL)
        if ((skb = skb_peek(&scp->data_xmit_queue)) != NULL)
                reduce_win = dn_nsp_clone_and_send(skb, GFP_ATOMIC);
                reduce_win = dn_nsp_clone_and_send(skb, GFP_ATOMIC);
 
 
        /*
        /*
         * If we've sent any frame more than once, we cut the
         * If we've sent any frame more than once, we cut the
         * send window size in half. There is always a minimum
         * send window size in half. There is always a minimum
         * window size of one available.
         * window size of one available.
         */
         */
recalc_window:
recalc_window:
        if (reduce_win) {
        if (reduce_win) {
                scp->snd_window >>= 1;
                scp->snd_window >>= 1;
                if (scp->snd_window < NSP_MIN_WINDOW)
                if (scp->snd_window < NSP_MIN_WINDOW)
                        scp->snd_window = NSP_MIN_WINDOW;
                        scp->snd_window = NSP_MIN_WINDOW;
        }
        }
}
}
 
 
int dn_nsp_xmit_timeout(struct sock *sk)
int dn_nsp_xmit_timeout(struct sock *sk)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
 
 
        dn_nsp_output(sk);
        dn_nsp_output(sk);
 
 
        if (skb_queue_len(&scp->data_xmit_queue) || skb_queue_len(&scp->other_xmit_queue))
        if (skb_queue_len(&scp->data_xmit_queue) || skb_queue_len(&scp->other_xmit_queue))
                scp->persist = dn_nsp_persist(sk);
                scp->persist = dn_nsp_persist(sk);
 
 
        return 0;
        return 0;
}
}
 
 
static inline unsigned char *dn_mk_common_header(struct dn_scp *scp, struct sk_buff *skb, unsigned char msgflag, int len)
static inline unsigned char *dn_mk_common_header(struct dn_scp *scp, struct sk_buff *skb, unsigned char msgflag, int len)
{
{
        unsigned char *ptr = skb_push(skb, len);
        unsigned char *ptr = skb_push(skb, len);
 
 
        if (len < 5)
        if (len < 5)
                BUG();
                BUG();
 
 
        *ptr++ = msgflag;
        *ptr++ = msgflag;
        *((unsigned short *)ptr) = scp->addrrem;
        *((unsigned short *)ptr) = scp->addrrem;
        ptr += 2;
        ptr += 2;
        *((unsigned short *)ptr) = scp->addrloc;
        *((unsigned short *)ptr) = scp->addrloc;
        ptr += 2;
        ptr += 2;
        return ptr;
        return ptr;
}
}
 
 
static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned char msgflag, int hlen, int other)
static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned char msgflag, int hlen, int other)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        unsigned short acknum = scp->numdat_rcv & 0x0FFF;
        unsigned short acknum = scp->numdat_rcv & 0x0FFF;
        unsigned short ackcrs = scp->numoth_rcv & 0x0FFF;
        unsigned short ackcrs = scp->numoth_rcv & 0x0FFF;
        unsigned short *ptr;
        unsigned short *ptr;
 
 
        if (hlen < 9)
        if (hlen < 9)
                BUG();
                BUG();
 
 
        scp->ackxmt_dat = acknum;
        scp->ackxmt_dat = acknum;
        scp->ackxmt_oth = ackcrs;
        scp->ackxmt_oth = ackcrs;
        acknum |= 0x8000;
        acknum |= 0x8000;
        ackcrs |= 0x8000;
        ackcrs |= 0x8000;
 
 
        /* If this is an "other data/ack" message, swap acknum and ackcrs */
        /* If this is an "other data/ack" message, swap acknum and ackcrs */
        if (other) {
        if (other) {
                unsigned short tmp = acknum;
                unsigned short tmp = acknum;
                acknum = ackcrs;
                acknum = ackcrs;
                ackcrs = tmp;
                ackcrs = tmp;
        }
        }
 
 
        /* Set "cross subchannel" bit in ackcrs */
        /* Set "cross subchannel" bit in ackcrs */
        ackcrs |= 0x2000;
        ackcrs |= 0x2000;
 
 
        ptr = (unsigned short *)dn_mk_common_header(scp, skb, msgflag, hlen);
        ptr = (unsigned short *)dn_mk_common_header(scp, skb, msgflag, hlen);
 
 
        *ptr++ = dn_htons(acknum);
        *ptr++ = dn_htons(acknum);
        *ptr++ = dn_htons(ackcrs);
        *ptr++ = dn_htons(ackcrs);
 
 
        return ptr;
        return ptr;
}
}
 
 
void dn_nsp_queue_xmit(struct sock *sk, struct sk_buff *skb, int gfp, int oth)
void dn_nsp_queue_xmit(struct sock *sk, struct sk_buff *skb, int gfp, int oth)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        unsigned long t = ((scp->nsp_srtt >> 2) + scp->nsp_rttvar) >> 1;
        unsigned long t = ((scp->nsp_srtt >> 2) + scp->nsp_rttvar) >> 1;
 
 
        /*
        /*
         * Slow start: If we have been idle for more than
         * Slow start: If we have been idle for more than
         * one RTT, then reset window to min size.
         * one RTT, then reset window to min size.
         */
         */
        if ((jiffies - scp->stamp) > t)
        if ((jiffies - scp->stamp) > t)
                scp->snd_window = NSP_MIN_WINDOW;
                scp->snd_window = NSP_MIN_WINDOW;
 
 
        /* printk(KERN_DEBUG "Window: %lu\n", scp->snd_window); */
        /* printk(KERN_DEBUG "Window: %lu\n", scp->snd_window); */
 
 
        cb->xmit_count = 0;
        cb->xmit_count = 0;
 
 
        if (oth)
        if (oth)
                skb_queue_tail(&scp->other_xmit_queue, skb);
                skb_queue_tail(&scp->other_xmit_queue, skb);
        else
        else
                skb_queue_tail(&scp->data_xmit_queue, skb);
                skb_queue_tail(&scp->data_xmit_queue, skb);
 
 
        if (scp->flowrem_sw != DN_SEND)
        if (scp->flowrem_sw != DN_SEND)
                return;
                return;
 
 
        dn_nsp_clone_and_send(skb, gfp);
        dn_nsp_clone_and_send(skb, gfp);
}
}
 
 
 
 
int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff_head *q, unsigned short acknum)
int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff_head *q, unsigned short acknum)
{
{
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        struct sk_buff *skb2, *list, *ack = NULL;
        struct sk_buff *skb2, *list, *ack = NULL;
        int wakeup = 0;
        int wakeup = 0;
        int try_retrans = 0;
        int try_retrans = 0;
        unsigned long reftime = cb->stamp;
        unsigned long reftime = cb->stamp;
        unsigned long pkttime;
        unsigned long pkttime;
        unsigned short xmit_count;
        unsigned short xmit_count;
        unsigned short segnum;
        unsigned short segnum;
 
 
        skb2 = q->next;
        skb2 = q->next;
        list = (struct sk_buff *)q;
        list = (struct sk_buff *)q;
        while(list != skb2) {
        while(list != skb2) {
                struct dn_skb_cb *cb2 = DN_SKB_CB(skb2);
                struct dn_skb_cb *cb2 = DN_SKB_CB(skb2);
 
 
                if (before_or_equal(cb2->segnum, acknum))
                if (before_or_equal(cb2->segnum, acknum))
                        ack = skb2;
                        ack = skb2;
 
 
                /* printk(KERN_DEBUG "ack: %s %04x %04x\n", ack ? "ACK" : "SKIP", (int)cb2->segnum, (int)acknum); */
                /* printk(KERN_DEBUG "ack: %s %04x %04x\n", ack ? "ACK" : "SKIP", (int)cb2->segnum, (int)acknum); */
 
 
                skb2 = skb2->next;
                skb2 = skb2->next;
 
 
                if (ack == NULL)
                if (ack == NULL)
                        continue;
                        continue;
 
 
                /* printk(KERN_DEBUG "check_xmit_queue: %04x, %d\n", acknum, cb2->xmit_count); */
                /* printk(KERN_DEBUG "check_xmit_queue: %04x, %d\n", acknum, cb2->xmit_count); */
 
 
                /* Does _last_ packet acked have xmit_count > 1 */
                /* Does _last_ packet acked have xmit_count > 1 */
                try_retrans = 0;
                try_retrans = 0;
                /* Remember to wake up the sending process */
                /* Remember to wake up the sending process */
                wakeup = 1;
                wakeup = 1;
                /* Keep various statistics */
                /* Keep various statistics */
                pkttime = cb2->stamp;
                pkttime = cb2->stamp;
                xmit_count = cb2->xmit_count;
                xmit_count = cb2->xmit_count;
                segnum = cb2->segnum;
                segnum = cb2->segnum;
                /* Remove and drop ack'ed packet */
                /* Remove and drop ack'ed packet */
                skb_unlink(ack);
                skb_unlink(ack);
                kfree_skb(ack);
                kfree_skb(ack);
                ack = NULL;
                ack = NULL;
 
 
                /*
                /*
                 * We don't expect to see acknowledgements for packets we
                 * We don't expect to see acknowledgements for packets we
                 * haven't sent yet.
                 * haven't sent yet.
                 */
                 */
                if (xmit_count == 0)
                if (xmit_count == 0)
                        BUG();
                        BUG();
                /*
                /*
                 * If the packet has only been sent once, we can use it
                 * If the packet has only been sent once, we can use it
                 * to calculate the RTT and also open the window a little
                 * to calculate the RTT and also open the window a little
                 * further.
                 * further.
                 */
                 */
                if (xmit_count == 1) {
                if (xmit_count == 1) {
                        if (equal(segnum, acknum))
                        if (equal(segnum, acknum))
                                dn_nsp_rtt(sk, (long)(pkttime - reftime));
                                dn_nsp_rtt(sk, (long)(pkttime - reftime));
 
 
                        if (scp->snd_window < scp->max_window)
                        if (scp->snd_window < scp->max_window)
                                scp->snd_window++;
                                scp->snd_window++;
                }
                }
 
 
                /*
                /*
                 * Packet has been sent more than once. If this is the last
                 * Packet has been sent more than once. If this is the last
                 * packet to be acknowledged then we want to send the next
                 * packet to be acknowledged then we want to send the next
                 * packet in the send queue again (assumes the remote host does
                 * packet in the send queue again (assumes the remote host does
                 * go-back-N error control).
                 * go-back-N error control).
                 */
                 */
                if (xmit_count > 1)
                if (xmit_count > 1)
                        try_retrans = 1;
                        try_retrans = 1;
        }
        }
 
 
        if (try_retrans)
        if (try_retrans)
                dn_nsp_output(sk);
                dn_nsp_output(sk);
 
 
        return wakeup;
        return wakeup;
}
}
 
 
void dn_nsp_send_data_ack(struct sock *sk)
void dn_nsp_send_data_ack(struct sock *sk)
{
{
        struct sk_buff *skb = NULL;
        struct sk_buff *skb = NULL;
 
 
        if ((skb = dn_alloc_skb(sk, 9, GFP_ATOMIC)) == NULL)
        if ((skb = dn_alloc_skb(sk, 9, GFP_ATOMIC)) == NULL)
                return;
                return;
 
 
        skb_reserve(skb, 9);
        skb_reserve(skb, 9);
        dn_mk_ack_header(sk, skb, 0x04, 9, 0);
        dn_mk_ack_header(sk, skb, 0x04, 9, 0);
        dn_nsp_send(skb);
        dn_nsp_send(skb);
}
}
 
 
void dn_nsp_send_oth_ack(struct sock *sk)
void dn_nsp_send_oth_ack(struct sock *sk)
{
{
        struct sk_buff *skb = NULL;
        struct sk_buff *skb = NULL;
 
 
        if ((skb = dn_alloc_skb(sk, 9, GFP_ATOMIC)) == NULL)
        if ((skb = dn_alloc_skb(sk, 9, GFP_ATOMIC)) == NULL)
                return;
                return;
 
 
        skb_reserve(skb, 9);
        skb_reserve(skb, 9);
        dn_mk_ack_header(sk, skb, 0x14, 9, 1);
        dn_mk_ack_header(sk, skb, 0x14, 9, 1);
        dn_nsp_send(skb);
        dn_nsp_send(skb);
}
}
 
 
 
 
void dn_send_conn_ack (struct sock *sk)
void dn_send_conn_ack (struct sock *sk)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        struct sk_buff *skb = NULL;
        struct sk_buff *skb = NULL;
        struct nsp_conn_ack_msg *msg;
        struct nsp_conn_ack_msg *msg;
 
 
        if ((skb = dn_alloc_skb(sk, 3, sk->allocation)) == NULL)
        if ((skb = dn_alloc_skb(sk, 3, sk->allocation)) == NULL)
                return;
                return;
 
 
        msg = (struct nsp_conn_ack_msg *)skb_put(skb, 3);
        msg = (struct nsp_conn_ack_msg *)skb_put(skb, 3);
        msg->msgflg = 0x24;
        msg->msgflg = 0x24;
        msg->dstaddr = scp->addrrem;
        msg->dstaddr = scp->addrrem;
 
 
        dn_nsp_send(skb);
        dn_nsp_send(skb);
}
}
 
 
void dn_nsp_delayed_ack(struct sock *sk)
void dn_nsp_delayed_ack(struct sock *sk)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
 
 
        if (scp->ackxmt_oth != scp->numoth_rcv)
        if (scp->ackxmt_oth != scp->numoth_rcv)
                dn_nsp_send_oth_ack(sk);
                dn_nsp_send_oth_ack(sk);
 
 
        if (scp->ackxmt_dat != scp->numdat_rcv)
        if (scp->ackxmt_dat != scp->numdat_rcv)
                dn_nsp_send_data_ack(sk);
                dn_nsp_send_data_ack(sk);
}
}
 
 
static int dn_nsp_retrans_conn_conf(struct sock *sk)
static int dn_nsp_retrans_conn_conf(struct sock *sk)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
 
 
        if (scp->state == DN_CC)
        if (scp->state == DN_CC)
                dn_send_conn_conf(sk, GFP_ATOMIC);
                dn_send_conn_conf(sk, GFP_ATOMIC);
 
 
        return 0;
        return 0;
}
}
 
 
void dn_send_conn_conf(struct sock *sk, int gfp)
void dn_send_conn_conf(struct sock *sk, int gfp)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        struct sk_buff *skb = NULL;
        struct sk_buff *skb = NULL;
        struct nsp_conn_init_msg *msg;
        struct nsp_conn_init_msg *msg;
        unsigned char len = scp->conndata_out.opt_optl;
        unsigned char len = scp->conndata_out.opt_optl;
 
 
        if ((skb = dn_alloc_skb(sk, 50 + scp->conndata_out.opt_optl, gfp)) == NULL)
        if ((skb = dn_alloc_skb(sk, 50 + scp->conndata_out.opt_optl, gfp)) == NULL)
                return;
                return;
 
 
        msg = (struct nsp_conn_init_msg *)skb_put(skb, sizeof(*msg));
        msg = (struct nsp_conn_init_msg *)skb_put(skb, sizeof(*msg));
        msg->msgflg = 0x28;
        msg->msgflg = 0x28;
        msg->dstaddr = scp->addrrem;
        msg->dstaddr = scp->addrrem;
        msg->srcaddr = scp->addrloc;
        msg->srcaddr = scp->addrloc;
        msg->services = scp->services_loc;
        msg->services = scp->services_loc;
        msg->info = scp->info_loc;
        msg->info = scp->info_loc;
        msg->segsize = dn_htons(scp->segsize_loc);
        msg->segsize = dn_htons(scp->segsize_loc);
 
 
        *skb_put(skb,1) = len;
        *skb_put(skb,1) = len;
 
 
        if (len > 0)
        if (len > 0)
                memcpy(skb_put(skb, len), scp->conndata_out.opt_data, len);
                memcpy(skb_put(skb, len), scp->conndata_out.opt_data, len);
 
 
 
 
        dn_nsp_send(skb);
        dn_nsp_send(skb);
 
 
        scp->persist = dn_nsp_persist(sk);
        scp->persist = dn_nsp_persist(sk);
        scp->persist_fxn = dn_nsp_retrans_conn_conf;
        scp->persist_fxn = dn_nsp_retrans_conn_conf;
}
}
 
 
 
 
static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
                        unsigned short reason, int gfp, struct dst_entry *dst,
                        unsigned short reason, int gfp, struct dst_entry *dst,
                        int ddl, unsigned char *dd, __u16 rem, __u16 loc)
                        int ddl, unsigned char *dd, __u16 rem, __u16 loc)
{
{
        struct sk_buff *skb = NULL;
        struct sk_buff *skb = NULL;
        int size = 7 + ddl + ((msgflg == NSP_DISCINIT) ? 1 : 0);
        int size = 7 + ddl + ((msgflg == NSP_DISCINIT) ? 1 : 0);
        unsigned char *msg;
        unsigned char *msg;
 
 
        if ((dst == NULL) || (rem == 0)) {
        if ((dst == NULL) || (rem == 0)) {
                if (net_ratelimit())
                if (net_ratelimit())
                        printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", (unsigned)rem, dst);
                        printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", (unsigned)rem, dst);
                return;
                return;
        }
        }
 
 
        if ((skb = dn_alloc_skb(sk, size, gfp)) == NULL)
        if ((skb = dn_alloc_skb(sk, size, gfp)) == NULL)
                return;
                return;
 
 
        msg = skb_put(skb, size);
        msg = skb_put(skb, size);
        *msg++ = msgflg;
        *msg++ = msgflg;
        *(__u16 *)msg = rem;
        *(__u16 *)msg = rem;
        msg += 2;
        msg += 2;
        *(__u16 *)msg = loc;
        *(__u16 *)msg = loc;
        msg += 2;
        msg += 2;
        *(__u16 *)msg = dn_htons(reason);
        *(__u16 *)msg = dn_htons(reason);
        msg += 2;
        msg += 2;
        if (msgflg == NSP_DISCINIT)
        if (msgflg == NSP_DISCINIT)
                *msg++ = ddl;
                *msg++ = ddl;
 
 
        if (ddl) {
        if (ddl) {
                memcpy(msg, dd, ddl);
                memcpy(msg, dd, ddl);
        }
        }
 
 
        /*
        /*
         * This doesn't go via the dn_nsp_send() fucntion since we need
         * This doesn't go via the dn_nsp_send() fucntion since we need
         * to be able to send disc packets out which have no socket
         * to be able to send disc packets out which have no socket
         * associations.
         * associations.
         */
         */
        skb->dst = dst_clone(dst);
        skb->dst = dst_clone(dst);
        skb->dst->output(skb);
        skb->dst->output(skb);
}
}
 
 
 
 
void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg,
void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg,
                        unsigned short reason, int gfp)
                        unsigned short reason, int gfp)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        int ddl = 0;
        int ddl = 0;
 
 
        if (msgflg == NSP_DISCINIT)
        if (msgflg == NSP_DISCINIT)
                ddl = scp->discdata_out.opt_optl;
                ddl = scp->discdata_out.opt_optl;
 
 
        if (reason == 0)
        if (reason == 0)
                reason = scp->discdata_out.opt_status;
                reason = scp->discdata_out.opt_status;
 
 
        dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->dst_cache, ddl,
        dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->dst_cache, ddl,
                scp->discdata_out.opt_data, scp->addrrem, scp->addrloc);
                scp->discdata_out.opt_data, scp->addrrem, scp->addrloc);
}
}
 
 
 
 
void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg,
void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg,
                        unsigned short reason)
                        unsigned short reason)
{
{
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        int ddl = 0;
        int ddl = 0;
        int gfp = GFP_ATOMIC;
        int gfp = GFP_ATOMIC;
 
 
        dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb->dst, ddl,
        dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb->dst, ddl,
                        NULL, cb->src_port, cb->dst_port);
                        NULL, cb->src_port, cb->dst_port);
}
}
 
 
 
 
void dn_nsp_send_link(struct sock *sk, unsigned char lsflags, char fcval)
void dn_nsp_send_link(struct sock *sk, unsigned char lsflags, char fcval)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        struct sk_buff *skb;
        struct sk_buff *skb;
        unsigned short *segnum;
        unsigned short *segnum;
        unsigned char *ptr;
        unsigned char *ptr;
        int gfp = GFP_ATOMIC;
        int gfp = GFP_ATOMIC;
 
 
        if ((skb = dn_alloc_skb(sk, 13, gfp)) == NULL)
        if ((skb = dn_alloc_skb(sk, 13, gfp)) == NULL)
                return;
                return;
 
 
        skb_reserve(skb, 13);
        skb_reserve(skb, 13);
        segnum = dn_mk_ack_header(sk, skb, 0x10, 13, 1);
        segnum = dn_mk_ack_header(sk, skb, 0x10, 13, 1);
        *segnum = dn_htons(scp->numoth);
        *segnum = dn_htons(scp->numoth);
        DN_SKB_CB(skb)->segnum = scp->numoth;
        DN_SKB_CB(skb)->segnum = scp->numoth;
        seq_add(&scp->numoth, 1);
        seq_add(&scp->numoth, 1);
        ptr = (unsigned char *)(segnum + 1);
        ptr = (unsigned char *)(segnum + 1);
        *ptr++ = lsflags;
        *ptr++ = lsflags;
        *ptr = fcval;
        *ptr = fcval;
 
 
        dn_nsp_queue_xmit(sk, skb, gfp, 1);
        dn_nsp_queue_xmit(sk, skb, gfp, 1);
 
 
        scp->persist = dn_nsp_persist(sk);
        scp->persist = dn_nsp_persist(sk);
        scp->persist_fxn = dn_nsp_xmit_timeout;
        scp->persist_fxn = dn_nsp_xmit_timeout;
}
}
 
 
static int dn_nsp_retrans_conninit(struct sock *sk)
static int dn_nsp_retrans_conninit(struct sock *sk)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
 
 
        if (scp->state == DN_CI)
        if (scp->state == DN_CI)
                dn_nsp_send_conninit(sk, NSP_RCI);
                dn_nsp_send_conninit(sk, NSP_RCI);
 
 
        return 0;
        return 0;
}
}
 
 
void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
{
{
        struct dn_scp *scp = DN_SK(sk);
        struct dn_scp *scp = DN_SK(sk);
        struct sk_buff *skb = NULL;
        struct sk_buff *skb = NULL;
        struct nsp_conn_init_msg *msg;
        struct nsp_conn_init_msg *msg;
        unsigned char aux;
        unsigned char aux;
        unsigned char menuver;
        unsigned char menuver;
        struct dn_skb_cb *cb;
        struct dn_skb_cb *cb;
        unsigned char type = 1;
        unsigned char type = 1;
 
 
        if ((skb = dn_alloc_skb(sk, 200, (msgflg == NSP_CI) ? sk->allocation : GFP_ATOMIC)) == NULL)
        if ((skb = dn_alloc_skb(sk, 200, (msgflg == NSP_CI) ? sk->allocation : GFP_ATOMIC)) == NULL)
                return;
                return;
 
 
        cb  = DN_SKB_CB(skb);
        cb  = DN_SKB_CB(skb);
        msg = (struct nsp_conn_init_msg *)skb_put(skb,sizeof(*msg));
        msg = (struct nsp_conn_init_msg *)skb_put(skb,sizeof(*msg));
 
 
        msg->msgflg     = msgflg;
        msg->msgflg     = msgflg;
        msg->dstaddr    = 0x0000;               /* Remote Node will assign it*/
        msg->dstaddr    = 0x0000;               /* Remote Node will assign it*/
 
 
        msg->srcaddr    = scp->addrloc;
        msg->srcaddr    = scp->addrloc;
        msg->services   = scp->services_loc;    /* Requested flow control    */
        msg->services   = scp->services_loc;    /* Requested flow control    */
        msg->info       = scp->info_loc;        /* Version Number            */
        msg->info       = scp->info_loc;        /* Version Number            */
        msg->segsize    = dn_htons(scp->segsize_loc);   /* Max segment size  */
        msg->segsize    = dn_htons(scp->segsize_loc);   /* Max segment size  */
 
 
        if (scp->peer.sdn_objnum)
        if (scp->peer.sdn_objnum)
                type = 0;
                type = 0;
 
 
        skb_put(skb, dn_sockaddr2username(&scp->peer, skb->tail, type));
        skb_put(skb, dn_sockaddr2username(&scp->peer, skb->tail, type));
        skb_put(skb, dn_sockaddr2username(&scp->addr, skb->tail, 2));
        skb_put(skb, dn_sockaddr2username(&scp->addr, skb->tail, 2));
 
 
        menuver = DN_MENUVER_ACC | DN_MENUVER_USR;
        menuver = DN_MENUVER_ACC | DN_MENUVER_USR;
        if (scp->peer.sdn_flags & SDF_PROXY)
        if (scp->peer.sdn_flags & SDF_PROXY)
                menuver |= DN_MENUVER_PRX;
                menuver |= DN_MENUVER_PRX;
        if (scp->peer.sdn_flags & SDF_UICPROXY)
        if (scp->peer.sdn_flags & SDF_UICPROXY)
                menuver |= DN_MENUVER_UIC;
                menuver |= DN_MENUVER_UIC;
 
 
        *skb_put(skb, 1) = menuver;     /* Menu Version         */
        *skb_put(skb, 1) = menuver;     /* Menu Version         */
 
 
        aux = scp->accessdata.acc_userl;
        aux = scp->accessdata.acc_userl;
        *skb_put(skb, 1) = aux;
        *skb_put(skb, 1) = aux;
        if (aux > 0)
        if (aux > 0)
        memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux);
        memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux);
 
 
        aux = scp->accessdata.acc_passl;
        aux = scp->accessdata.acc_passl;
        *skb_put(skb, 1) = aux;
        *skb_put(skb, 1) = aux;
        if (aux > 0)
        if (aux > 0)
        memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux);
        memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux);
 
 
        aux = scp->accessdata.acc_accl;
        aux = scp->accessdata.acc_accl;
        *skb_put(skb, 1) = aux;
        *skb_put(skb, 1) = aux;
        if (aux > 0)
        if (aux > 0)
        memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
        memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
 
 
        aux = scp->conndata_out.opt_optl;
        aux = scp->conndata_out.opt_optl;
        *skb_put(skb, 1) = aux;
        *skb_put(skb, 1) = aux;
        if (aux > 0)
        if (aux > 0)
        memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux);
        memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux);
 
 
        scp->persist = dn_nsp_persist(sk);
        scp->persist = dn_nsp_persist(sk);
        scp->persist_fxn = dn_nsp_retrans_conninit;
        scp->persist_fxn = dn_nsp_retrans_conninit;
 
 
        cb->rt_flags = DN_RT_F_RQR;
        cb->rt_flags = DN_RT_F_RQR;
 
 
        dn_nsp_send(skb);
        dn_nsp_send(skb);
}
}
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.