diff options
Diffstat (limited to 'net/ax25/ax25_in.c')
-rw-r--r-- | net/ax25/ax25_in.c | 984 |
1 files changed, 655 insertions, 329 deletions
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 7c1484d6e..1e51005c4 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -1,68 +1,333 @@ /* - * AX.25 release 037 + * ax25_in.c: Routines for processing of incoming frames (NEW-AX.25) * - * This code REQUIRES 2.1.15 or higher/ NET3.038 + * Authors: Jens David (DG1KJD), Matthias Welwarsky (DG2FEF), + * Jonathan (G4KLX), Alan Cox (GW4PTS), HaJo (DD8NE) * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. + * Comment: Most of this code is based on the SDL diagrams published in the + * ARRL Computer Networking Conference papers. The diagrams have mi + * in them, but are mostly correct. Before you modify the code coul + * read the SDL diagrams as the code is not obvious and probably ve + * easy to break; * - * Most of this code is based on the SDL diagrams published in the 7th - * ARRL Computer Networking Conference papers. The diagrams have mistakes - * in them, but are mostly correct. Before you modify the code could you - * read the SDL diagrams as the code is not obvious and probably very - * easy to break; + * Changelog: * - * History - * AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams. - * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from - * the sock structure. - * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. - * Jonathan(G4KLX) Added IP mode registration. - * AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception. - * Upgraded state machine for SABME. - * Added arbitrary protocol id support. - * AX.25 031 Joerg(DL1BKE) Added DAMA support - * HaJo(DD8NE) Added Idle Disc Timer T5 - * Joerg(DL1BKE) Renamed it to "IDLE" with a slightly - * different behaviour. Fixed defrag - * routine (I hope) - * AX.25 032 Darryl(G7LED) AX.25 segmentation fixed. - * AX.25 033 Jonathan(G4KLX) Remove auto-router. - * Modularisation changes. - * AX.25 035 Hans(PE1AYX) Fixed interface to IP layer. - * AX.25 036 Jonathan(G4KLX) Move DAMA code into own file. - * Joerg(DL1BKE) Fixed DAMA Slave. - * AX.25 037 Jonathan(G4KLX) New timer architecture. - * Thomas(DL9SAU) Fixed missing initialization of skb->protocol. + * License: This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. */ #include <linux/config.h> -#include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> -#include <linux/in.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/string.h> -#include <linux/sockios.h> -#include <linux/net.h> -#include <net/ax25.h> -#include <linux/inet.h> -#include <linux/netdevice.h> #include <linux/skbuff.h> -#include <linux/netfilter.h> +#include <linux/netdevice.h> #include <net/sock.h> -#include <net/ip.h> /* For ip_rcv */ -#include <net/arp.h> /* For arp_rcv */ -#include <asm/uaccess.h> -#include <asm/system.h> -#include <linux/fcntl.h> -#include <linux/mm.h> -#include <linux/interrupt.h> +#include <net/ip.h> +#include <net/arp.h> +#include <net/ax25.h> +#include <net/ax25dev.h> + +#include "af_ax25.h" +#include "ax25_route.h" +#include "ax25_ddi.h" +#include "ax25_in.h" +#include "ax25_lapb.h" +#include "ax25_core.h" +#include "ax25_subr.h" +#include "ax25_netlink.h" + +static int ax25_rx_fragment(ax25_cb*, struct sk_buff*); +static void ax25_decode(ax25_cb*, struct sk_buff*, ax25_pktinfo*); +static struct sock* ax25_find_socket(ax25_address*, ax25_address*, struct net_device*, int); +static int ax25_match_addr(ax25_address*, struct net_device*); +/* static void ax25_send_to_raw(struct sock*, struct sk_buff*, int); */ +static int ax25_rcv(struct sk_buff*, struct net_device*, struct packet_type*); + +/* + * Packet type registration data + */ +struct packet_type ax25_packet_type = +{ + 0, /* MUTTER ntohs(ETH_P_AX25),*/ + 0, /* copy */ + ax25_rcv, + NULL, + NULL, +}; + +/* + * Higher level upcall for a LAPB frame + */ +int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, ax25_pktinfo* pkt_info) +{ + struct net_device *dev = skb->dev; + + ax25_decode(ax25, skb, pkt_info); + ax25_dev_set_dama(dev, pkt_info->dama); + if (pkt_info->pf && (pkt_info->cmdrsp == AX25_COMMAND)) + AX25_PTR(dev)->dama_polled = 1; + return ax25_lapb_table[ax25->state](ax25, skb, pkt_info); +} + +/* + * Resequencer + */ +static inline unsigned int ax25_csum_skb(struct sk_buff *skb) +{ + unsigned char *cp = skb->data; + unsigned int csum = 0; + + while (cp < (skb->data + skb->len)) + csum += *cp++; + + return csum; +} + +void ax25_reseq_update(ax25_cb* ax25, struct sk_buff *skb, int ns) +{ + if (ax25->reseq[ns].skb != NULL) + return; + + ax25->reseq[ns].csum = ax25_csum_skb(skb); +} + +int ax25_reseq_in(ax25_cb *ax25, struct sk_buff *skb, int ns, int pf) +{ + unsigned int csum; + + /* + * if either + * - the poll flag is set + * - the slot is not empty + * - we've already seen this frame + * drop it + */ + + if (pf || ax25->reseq[ns].skb != NULL || + ax25->reseq[ns].csum == (csum = ax25_csum_skb(skb))) + return 0; + + /* + * otherwise queue it + */ + ax25->reseq[ns].skb = skb; + ax25->reseq[ns].csum = csum; + + return 1; +} + +void ax25_reseq_out(ax25_cb *ax25) +{ + struct sk_buff *skb; + + while ((skb = ax25->reseq[ax25->vr].skb) != NULL && ax25_rx_iframe(ax25, skb)) { + ax25->reseq[ax25->vr].skb = NULL; + ax25->vr = (ax25->vr+1) & ax25->seqmask; + } +} + +/* + * This is where all valid I frames are sent to, to be dispatched to + * whichever protocol requires them. + */ +int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) +{ + ax25_cb *peer; + unsigned char pid = *skb->data; + struct sock *sk = NULL; + int queued = 0; + + int (*func)(struct sk_buff *, ax25_cb *); + + if (ax25->device) { + AX25_PTR(ax25->device)->rx_iframes++; + AX25_PTR(ax25->device)->rx_bytes += skb->len; + } + + ax25_clr_cond(ax25, AX25_COND_SETUP); + + /* + * don't take any more data if we're about to close + * the connection. + */ + if (ax25->condition & AX25_COND_RELEASE) { + ax25_set_cond(ax25, AX25_COND_OWN_RX_BUSY); + kfree_skb(skb); + return 1; + } + + /* + * we're only digipeating, don't care about pid + * and idle timeouts. + */ + if ((peer = ax25->peer) != NULL) { + int max_qlen; + + /* + * don't queue any more data if the peer is just about to + * be disconnected. + */ + if (peer->state < AX25_STATE_3 || peer->condition & AX25_COND_RELEASE) { + kfree_skb(skb); + return 1; + } + + skb_queue_tail(&peer->write_queue, skb); + + /* + * check the length of write_queue, set OWN_RX_BUSY if + * enough queued. + */ + max_qlen = peer->seqmask << 1; + if (max_qlen > 16) + max_qlen = 16; + if (skb_queue_len(&peer->write_queue) > max_qlen) { + ax25->condition |= AX25_COND_OWN_RX_BUSY; + } + ax25_kick(peer); + + return 1; + } + + ax25->idletimer = ax25->idle; + + if (pid == AX25_P_SEGMENT) { + skb_pull(skb, 1); + queued = ax25_rx_fragment(ax25, skb); + + } else if ((func = ax25_protocol_function(pid)) != NULL) { + skb_pull(skb, 1); /* Remove PID */ + queued = func(skb, ax25); + + } else if ((sk = ax25->sk) != NULL) { + struct sk_buff *oskb; + /* + * check if we have frames left in ax25->rcv_queue, these + * must be delivered first to maintain the sequence. + */ + while ((oskb = skb_peek(&ax25->rcv_queue)) != NULL) { + if (sk->shutdown & RCV_SHUTDOWN) + break; + if (atomic_read(&sk->rmem_alloc) + oskb->truesize < sk->rcvbuf) { + skb_dequeue(&ax25->rcv_queue); + sock_queue_rcv_skb(sk, oskb); + } else + break; + } + if (oskb == NULL) + ax25->condition &= ~AX25_COND_OWN_RX_BUSY; + + /* + * now handle the frame that has just come in. + */ + if (ax25->pidincl || sk->protocol == pid) { + if (sk->shutdown & RCV_SHUTDOWN) { + ax25->condition |= AX25_COND_OWN_RX_BUSY; + kfree_skb(skb); + } else if (sock_queue_rcv_skb(sk, skb) != 0) { + /* + * no space left on the socket, become busy + * but keep queueing up the data. + */ + ax25->condition |= AX25_COND_OWN_RX_BUSY; + + /* + * don't queue an infinite amount of + * data, 10 frames should be enough + * and we'll send an RNR anyway. If + * the peer keeps bombing us with + * valid iframes, "return 0" forces + * the l2 to drop the frame without + * ACK'ng it. This will produce heavy + * load on the channel due to constantly + * retransmitted frames, but we cannot + * just drop the packets, the application + * cannot handle the data loss induced. + */ + if (skb_queue_len(&ax25->rcv_queue) < ax25->seqmask) + skb_queue_tail(&ax25->rcv_queue, skb); + else + return 0; + } + queued = 1; + } + } + + /* + * this is a kludge to satisfy the IMHO broken interface + * between the L2 and upper protocol handlers. There was no + * handler for the PID and the socket didn't accept the PID + * either, so we free the buffer and pretend to have queued + * it. + */ + if (!queued) + kfree_skb(skb); + return 1; +} + +/* ---------------------------------------------------------------------*/ + +struct sock *ax25_make_new(struct sock *osk, struct net_device *dev) +{ + struct sock *sk; + ax25_cb *ax25; + + if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1)) == NULL) + return NULL; + + if ((ax25 = ax25_create_cb()) == NULL) { + sk_free(sk); + return NULL; + } + + switch (osk->type) { + case SOCK_DGRAM: + break; + case SOCK_SEQPACKET: + break; + default: + sk_free(sk); + ax25_free_cb(ax25); + return NULL; + } + + sock_init_data(NULL, sk); + + sk->destruct = ax25_free_sock; + sk->type = osk->type; + sk->socket = osk->socket; + sk->priority = osk->priority; + sk->protocol = osk->protocol; + sk->rcvbuf = osk->rcvbuf; + sk->sndbuf = osk->sndbuf; + sk->debug = osk->debug; + sk->state = TCP_ESTABLISHED; + sk->sleep = osk->sleep; + sk->zapped = osk->zapped; + + ax25->seqmask = osk->protinfo.ax25->seqmask; + ax25->backoff = osk->protinfo.ax25->backoff; + ax25->pidincl = osk->protinfo.ax25->pidincl; + ax25->iamdigi = osk->protinfo.ax25->iamdigi; + ax25->rtt = osk->protinfo.ax25->rtt; + ax25->t1 = osk->protinfo.ax25->t1; + ax25->t2 = osk->protinfo.ax25->t2; + ax25->t3 = osk->protinfo.ax25->t3; + ax25->n2 = osk->protinfo.ax25->n2; + ax25->idle = osk->protinfo.ax25->idle; + ax25->paclen = osk->protinfo.ax25->paclen; + ax25->window = osk->protinfo.ax25->window; + + ax25->device = dev; + ax25->addr = osk->protinfo.ax25->addr; + + sk->protinfo.ax25 = ax25; + ax25->sk = sk; + + return sk; +} /* * Given a fragment, queue it on the fragment queue and if the fragment @@ -83,16 +348,15 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) /* Last fragment received ? */ if (ax25->fragno == 0) { - if ((skbn = alloc_skb(AX25_MAX_HEADER_LEN + ax25->fraglen, GFP_ATOMIC)) == NULL) { + if ((skbn = alloc_skb(MAX_HEADER + ax25->fraglen, GFP_ATOMIC)) == NULL) { while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) kfree_skb(skbo); return 1; } - skb_reserve(skbn, AX25_MAX_HEADER_LEN); + skb_reserve(skbn, MAX_HEADER); - skbn->dev = ax25->ax25_dev->dev; - skbn->h.raw = skbn->data; + skbn->dev = ax25->device; skbn->nh.raw = skbn->data; /* Copy data from the fragments */ @@ -126,360 +390,422 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) return 0; } + /* - * This is where all valid I frames are sent to, to be dispatched to - * whichever protocol requires them. + * This routine is the centralised routine for parsing the control + * information for the different frame formats. */ -int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) +static void ax25_decode(ax25_cb *ax25, struct sk_buff *skb, ax25_pktinfo *pkt_info) { - int (*func)(struct sk_buff *, ax25_cb *); - volatile int queued = 0; - unsigned char pid; - - if (skb == NULL) return 0; - - ax25_start_idletimer(ax25); + unsigned char *frame; + + frame = skb->data; + pkt_info->frametype = AX25_ILLEGAL; + pkt_info->ns = pkt_info->nr = pkt_info->pf = 0; + + if (ax25->seqmask == AX25_SEQMASK) { + if ((frame[0] & AX25_S) == 0) { + pkt_info->frametype = AX25_I; /* I frame - carries NR/NS/PF */ + pkt_info->ns = (frame[0] >> 1) & 0x07; + pkt_info->nr = (frame[0] >> 5) & 0x07; + pkt_info->pf = frame[0] & AX25_PF; + } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */ + pkt_info->frametype = frame[0] & 0x0F; + pkt_info->nr = (frame[0] >> 5) & 0x07; + pkt_info->pf = frame[0] & AX25_PF; + } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */ + pkt_info->frametype = frame[0] & ~AX25_PF; + pkt_info->pf = frame[0] & AX25_PF; + } + skb_pull(skb, 1); + } else { + if ((frame[0] & AX25_S) == 0) { + pkt_info->frametype = AX25_I; /* I frame - carries NR/NS/PF */ + pkt_info->ns = (frame[0] >> 1) & 0x7F; + pkt_info->nr = (frame[1] >> 1) & 0x7F; + pkt_info->pf = frame[1] & AX25_EPF; + skb_pull(skb, 2); + } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */ + pkt_info->frametype = frame[0] & 0x0F; + pkt_info->nr = (frame[1] >> 1) & 0x7F; + pkt_info->pf = frame[1] & AX25_EPF; + skb_pull(skb, 2); + } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */ + pkt_info->frametype = frame[0] & ~AX25_PF; + pkt_info->pf = frame[0] & AX25_PF; + skb_pull(skb, 1); + } + } +} - pid = *skb->data; +/* ---------------------------------------------------------------------*/ +/* + * Find a control block that wants to accept the SABM we have just + * received. + */ +ax25_cb *ax25_find_listener(ax25_address *addr, int digi, struct net_device *dev) +{ + ax25_cb *s; -#ifdef CONFIG_INET - if (pid == AX25_P_IP) { - /* working around a TCP bug to keep additional listeners - * happy. TCP re-uses the buffer and destroys the original - * content. - */ - struct sk_buff *skbn = skb_copy(skb, GFP_ATOMIC); - if (skbn != NULL) { - kfree_skb(skb); - skb = skbn; - } + if (dev != NULL) + if ((s = ax25_dev_find_listener(addr, digi, dev)) != NULL) + return s; - skb_pull(skb, 1); /* Remove PID */ - skb->h.raw = skb->data; - skb->nh.raw = skb->data; - skb->dev = ax25->ax25_dev->dev; - skb->pkt_type = PACKET_HOST; - skb->protocol = htons(ETH_P_IP); - ip_rcv(skb, skb->dev, NULL); /* Wrong ptype */ - return 1; - } -#endif - if (pid == AX25_P_SEGMENT) { - skb_pull(skb, 1); /* Remove PID */ - return ax25_rx_fragment(ax25, skb); + for (s = ax25_list; s != NULL; s = s->next) { + if (s->state == AX25_LISTEN + && s->iamdigi == digi + && !ax25cmp(&s->addr.src, addr)) + return s; } + return NULL; +} - if ((func = ax25_protocol_function(pid)) != NULL) { - skb_pull(skb, 1); /* Remove PID */ - return (*func)(skb, ax25); - } +/* ---------------------------------------------------------------------*/ +/* + * Find an AX.25 socket given both ends. + */ +static struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, struct net_device *dev, int type) +{ + ax25_cb *s; + struct sock *sk; - if (ax25->sk != NULL && ax25->ax25_dev->values[AX25_VALUES_CONMODE] == 2) { - if ((!ax25->pidincl && ax25->sk->protocol == pid) || ax25->pidincl) { - if (sock_queue_rcv_skb(ax25->sk, skb) == 0) - queued = 1; - else - ax25->condition |= AX25_COND_OWN_RX_BUSY; + if (dev != NULL) + if ((sk = ax25_dev_find_socket(my_addr, dest_addr, dev, type)) != NULL) + return sk; + + for (s = ax25_list; s != NULL; s = s->next) { + if (s->sk != NULL && s->sk->type == type + && !ax25cmp(&s->addr.src, my_addr) + && !ax25cmp(&s->addr.dest, dest_addr)) + { + return s->sk; } } + return NULL; +} + +/* ---------------------------------------------------------------------*/ - return queued; +static int ax25_match_addr(ax25_address *addr, struct net_device *dev) +{ + ax25_cb *s; + + if (dev != NULL && ax25_dev_match_addr(addr, dev)) + return 1; + + for (s = ax25_list; s != NULL; s = s->next) { + if (s->state == AX25_LISTEN && s->sk == NULL && ax25cmp(&s->addr.src, addr) == 0) + return 1; + } + return 0; } +/* ---------------------------------------------------------------------*/ + +#ifdef notdef /* - * Higher level upcall for a LAPB frame + * this is completely broken. + * + * it depends on that sk is the first of a linked list of sockets + * and traverses the list to find them all, cloning the packet if the + * protocol and socket type both match. */ -static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama) +static void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto) { - int queued = 0; + struct sk_buff *copy; - if (ax25->state == AX25_STATE_0) - return 0; + while (sk != NULL) { + if (sk->type == SOCK_RAW && + sk->protocol == proto && + atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { + if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL) + return; - switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - queued = ax25_std_frame_in(ax25, skb, type); - break; + if (sock_queue_rcv_skb(sk, copy) != 0) + kfree_skb(copy); + } -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - if (dama || ax25->ax25_dev->dama.slave) - queued = ax25_ds_frame_in(ax25, skb, type); - else - queued = ax25_std_frame_in(ax25, skb, type); - break; -#endif + sk = sk->next; } - - return queued; } +#endif -static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *dev_addr, struct packet_type *ptype) +/* ---------------------------------------------------------------------*/ + +static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype) { struct sock *make; struct sock *sk; - int type = 0; - ax25_digi dp, reverse_dp; - ax25_cb *ax25; - ax25_address src, dest; - ax25_address *next_digi = NULL; - ax25_dev *ax25_dev; - struct sock *raw; - int mine = 0; - int dama; + ax25_cb *ax25, *peer = NULL; + ax25_address *next_digi; + ax25_pktinfo pinf; + ax25_addr_t reverse_addr; + int queued; /* * Process the AX.25/LAPB frame. */ - skb->h.raw = skb->data; - - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { - kfree_skb(skb); - return 0; - } + skb->sk = NULL; + queued = 0; + AX25_PTR(dev)->dama_polled = 0; /* - * Parse the address header. + * TODO: packet filter */ - - if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) { - kfree_skb(skb); - return 0; - } +#ifdef undef + if (call_in_firewall(PF_AX25, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) + goto out_normal; +#endif /* - * Ours perhaps ? + * Parse the frame and Pull of the AX.25 headers + * leaving the CTRL/PID byte */ - if (dp.lastrepeat + 1 < dp.ndigi) /* Not yet digipeated completely */ - next_digi = &dp.calls[dp.lastrepeat + 1]; + if (ax25_parse_addr(skb->data, skb->len, &pinf) == NULL) + goto out_normal; + skb_pull(skb, ax25_sizeof_addr(&pinf.addr)); + /* - * Pull of the AX.25 headers leaving the CTRL/PID bytes + * Steps to perform while processing the frame, fast path'd for + * digipeating. */ - skb_pull(skb, ax25_addr_size(&dp)); - - /* For our port addresses ? */ - if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi) - mine = 1; - - /* Also match on any registered callsign from L3/4 */ - if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi) - mine = 1; - - /* UI frame - bypass LAPB processing */ - if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) { - skb->h.raw = skb->data + 2; /* skip control and pid */ - - if ((raw = ax25_addr_match(&dest)) != NULL) - ax25_send_to_raw(raw, skb, skb->data[1]); - - if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { - kfree_skb(skb); + next_digi = NULL; + if (pinf.addr.lastrepeat + 1 < pinf.addr.dcount) { + /* Not yet digipeated completely */ + struct net_device *out_dev; + next_digi = &pinf.addr.digipeater[pinf.addr.lastrepeat + 1]; + + /* check the frame type. do the easy thing first */ + if ((*skb->data & ~AX25_PF) == AX25_UI) { + /* digipeat UI frame */ + + /* check if next_digi matches one of our interfaces */ + if ((out_dev = ax25rtr_get_dev(next_digi)) == NULL) + goto out_normal; + + /* rebuild the header and transmit the frame */ + out_dev = ax25_rt_set_addr(&reverse_addr, &pinf.addr, dev, out_dev); + skb->nh.raw = skb->data; + skb_push(skb, ax25_sizeof_addr(&reverse_addr)); + ax25_build_addr(skb->data, &reverse_addr, pinf.cmdrsp, AX25_SEQMASK); + ax25_send_unproto(skb, out_dev); return 0; } - /* Now we are pointing at the pid byte */ - switch (skb->data[1]) { -#ifdef CONFIG_INET - case AX25_P_IP: - skb_pull(skb,2); /* drop PID/CTRL */ - skb->h.raw = skb->data; - skb->nh.raw = skb->data; - skb->dev = dev; - skb->pkt_type = PACKET_HOST; - skb->protocol = htons(ETH_P_IP); - ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ - break; + ax25_invert_addr(&pinf.addr, &reverse_addr); - case AX25_P_ARP: - skb_pull(skb,2); - skb->h.raw = skb->data; - skb->nh.raw = skb->data; - skb->dev = dev; - skb->pkt_type = PACKET_HOST; - skb->protocol = htons(ETH_P_ARP); - arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ - break; -#endif - case AX25_P_TEXT: - /* Now find a suitable dgram socket */ - if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) { - if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) { - kfree_skb(skb); - } else { - /* - * Remove the control and PID. - */ - skb_pull(skb, 2); - if (sock_queue_rcv_skb(sk, skb) != 0) - kfree_skb(skb); - } - } else { - kfree_skb(skb); - } - break; - - default: - kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */ - break; + if ((ax25 = ax25_find_cb(&reverse_addr, dev)) != NULL) { + /* no UI, but matches a given context */ + queued = ax25_process_rx_frame(ax25, skb, &pinf); + goto out_queued; } - return 0; - } + if ((*skb->data & ~AX25_PF) == AX25_SABM || (*skb->data & ~AX25_PF) == AX25_SABME) { + if ((ax25 = ax25_find_listener(next_digi, 1, dev)) != NULL) + goto listener_found; + if ((out_dev = ax25rtr_get_dev(next_digi)) == NULL) + goto out_normal; + if ((peer = ax25_create_cb()) == NULL) + goto out_normal; + if ((ax25 = ax25_create_cb()) == NULL) { + ax25_free_cb(peer); + goto out_normal; + } - /* - * Is connected mode supported on this device ? - * If not, should we DM the incoming frame (except DMs) or - * silently ignore them. For now we stay quiet. - */ - if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) { - kfree_skb(skb); - return 0; - } + out_dev = ax25_rt_set_addr(&peer->addr, &pinf.addr, dev, out_dev); + ax25_fillin_cb(peer, out_dev); + ax25_nlpost_route(&pinf, dev); - /* LAPB */ + /* set up the new control block */ + ax25_fillin_cb(ax25, dev); + ax25->addr = reverse_addr; - /* AX.25 state 1-4 */ + if ((*skb->data & ~AX25_PF) == AX25_SABME) { + ax25->seqmask = AX25_ESEQMASK; + ax25->window = ax25_dev_get_value(dev, AX25_VALUES_EWINDOW); + } else { + ax25->seqmask = AX25_SEQMASK; + ax25->window = ax25_dev_get_value(dev, AX25_VALUES_WINDOW); + } - ax25_digi_invert(&dp, &reverse_dp); + /* crosslink the peers */ + ax25->peer = peer; + peer->peer = ax25; - if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) { - /* - * Process the frame. If it is queued up internally it returns one otherwise we - * free it immediately. This routine itself wakes the user context layers so we - * do no further work - */ - if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) - kfree_skb(skb); + /* set window and modulus */ + peer->window = ax25->window; + peer->seqmask = ax25->seqmask; - return 0; - } + ax25->killtimer = 30 * AX25_SLOWHZ; + ax25->state = AX25_STATE_0; + ax25_insert_cb(ax25); - /* AX.25 state 0 (disconnected) */ + peer->state = AX25_STATE_1; + ax25_insert_cb(peer); + if (peer->seqmask == AX25_SEQMASK) + ax25_tx_command(peer, AX25_SABM, AX25_POLLON); + else + ax25_tx_command(peer, AX25_SABME, AX25_POLLON); - /* a) received not a SABM(E) */ + goto out_normal; + } - if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) { /* - * Never reply to a DM. Also ignore any connects for - * addresses that are not our interfaces and not a socket. + * the packet was no UI or SABM(E) and didn't match an existing + * context. If it's via us, digipeat blindly. */ - if ((*skb->data & ~AX25_PF) != AX25_DM && mine) - ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb); + /* check if next_digi matches one of our interfaces */ + if ((out_dev = ax25rtr_get_dev(next_digi)) == NULL) + goto out_normal; + + /* rebuild the header and transmit the frame */ + out_dev = ax25_rt_set_addr(&reverse_addr, &pinf.addr, dev, out_dev); + skb->nh.raw = skb->data; + skb_push(skb, ax25_sizeof_addr(&reverse_addr)); + ax25_build_addr(skb->data, &reverse_addr, pinf.cmdrsp, AX25_SEQMASK); + ax25_send_unproto(skb, out_dev); return 0; } - /* b) received SABM(E) */ - - if (dp.lastrepeat + 1 == dp.ndigi) - sk = ax25_find_listener(&dest, 0, dev, SOCK_SEQPACKET); - else - sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET); + /* + * UI frame - bypass LAPB processing + */ + if ((*skb->data & ~0x10) == AX25_UI) { + int queued = 0; + int pid; + /* skip control and pid */ + skb->nh.raw = skb->data + 2; - if (sk != NULL) { - if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, ax25_dev)) == NULL) { - if (mine) ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb); - return 0; - } + /* copy the datagram to all raw sockets */ +/* ax25_send_to_raw(&dest, skb, dev); */ - ax25 = make->protinfo.ax25; - skb_set_owner_r(skb, make); - skb_queue_head(&sk->receive_queue, skb); + /* if it's not a broadcast or one of our floating listeners, drop it */ + if (!ax25_match_addr(&pinf.addr.dest, dev) + && ax25cmp(&pinf.addr.dest, (ax25_address *)dev->broadcast)) + goto out_normal; - make->state = TCP_ESTABLISHED; - make->pair = sk; + /* Now we are pointing at the pid byte */ + switch (pid = skb->data[1]) { + int (*func)(struct sk_buff *, ax25_cb *); - sk->ack_backlog++; - } else { - if (!mine) { - kfree_skb(skb); - return 0; - } + case AX25_P_TEXT: + /* Now find a suitable dgram socket */ + if ((sk = ax25_find_socket(&pinf.addr.dest, &pinf.addr.src, dev, SOCK_DGRAM)) != NULL) { + if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) { + kfree_skb(skb); + } else { + /* + * Remove the control and PID. + */ + skb_pull(skb, 2); + if (sock_queue_rcv_skb(sk, skb) != 0) + kfree_skb(skb); + } + } else { + kfree_skb(skb); + } + break; - if ((ax25 = ax25_create_cb()) == NULL) { - ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb); - return 0; + default: + if ((func = ax25_protocol_function(pid)) != NULL) { + skb_pull(skb, 2); /* Remove CTL/PID */ + queued = func(skb, NULL); + } + if (!queued) + kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */ + break; } - ax25_fillin_cb(ax25, ax25_dev); + return 0; } - ax25->source_addr = dest; - ax25->dest_addr = src; - + /* LAPB */ /* - * Sort out any digipeated paths. + * invert the digipeater path and try to find a context for the + * received packet. */ - if (dp.ndigi != 0 && ax25->digipeat == NULL && (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - kfree_skb(skb); - ax25_destroy_socket(ax25); - return 0; + ax25_invert_addr(&pinf.addr, &reverse_addr); + if ((ax25 = ax25_find_cb(&reverse_addr, dev)) != NULL) { + /* + * Process the frame. If it is queued up internally it returns one otherwise we + * free it immediately. This routine itself wakes the user context layers so we + * do no further work + */ + queued = ax25_process_rx_frame(ax25, skb, &pinf); + goto out_queued; } - if (dp.ndigi == 0) { - if (ax25->digipeat != NULL) { - kfree(ax25->digipeat); - ax25->digipeat = NULL; + if ((ax25 = ax25_find_listener(&pinf.addr.dest, 0, dev)) != NULL) { + listener_found: + /* + * if this frame is not a SABM(E) return DM to the sender. + * it belongs to a stale connection. maybe we have rebootet or the + * peer didn't see our UA/DM + */ + if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) { + ax25_return_dm(dev, &pinf); + goto out_normal; } - } else { - /* Reverse the source SABM's path */ - memcpy(&ax25->digipeat, &reverse_dp, sizeof(ax25_digi)); - } - if ((*skb->data & ~AX25_PF) == AX25_SABME) { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; - } - - ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE); + /* ok, we have a listener */ + ax25_nlpost_route(&pinf, dev); + if ((sk = ax25->sk) != NULL) { + /* the listener is a socket */ + if (sk->type != SOCK_SEQPACKET || sk->state != TCP_LISTEN) + goto out_normal; -#ifdef CONFIG_AX25_DAMA_SLAVE - if (dama && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) - ax25_dama_on(ax25); -#endif + if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) { + ax25_return_dm(dev, &pinf); + goto out_normal; + } + skb->sk = make; + make->state = TCP_ESTABLISHED; + make->pair = sk; + ax25 = make->protinfo.ax25; + skb_queue_head(&sk->receive_queue, skb); + sk->ack_backlog++; + if (!sk->dead) + sk->data_ready(sk, skb->len); + queued = 1; + } else { + /* + * the listener is no socket, must be a callsign registered + * by a higher protocol, we just take the connection + */ + if ((ax25 = ax25_create_cb()) == NULL) { + ax25_return_dm(dev, &pinf); + goto out_normal; + } + ax25->slcomp_enable = ax25_rt_mode_get(&pinf.addr.src) == 'C'; + } - ax25->state = AX25_STATE_3; + /* set up the new control block */ + ax25_fillin_cb(ax25, dev); + ax25->addr = reverse_addr; - ax25_insert_socket(ax25); + if ((*skb->data & ~AX25_PF) == AX25_SABME) { + ax25->seqmask = AX25_ESEQMASK; + ax25->window = ax25_dev_get_value(dev, AX25_VALUES_EWINDOW); + } else { + ax25->seqmask = AX25_SEQMASK; + ax25->window = ax25_dev_get_value(dev, AX25_VALUES_WINDOW); + } - ax25_start_heartbeat(ax25); - ax25_start_t3timer(ax25); - ax25_start_idletimer(ax25); + ax25->device = dev; + ax25->wrt_timer = ax25->t3; + ax25->idletimer = ax25->idle; + ax25->state = AX25_STATE_3; + ax25_insert_cb(ax25); + ax25_tx_response(ax25, AX25_UA, AX25_POLLON); + } - if (sk != NULL) { - if (!sk->dead) - sk->data_ready(sk, skb->len); - } else { + out_queued: + if (!queued) { + out_normal: kfree_skb(skb); } - return 0; } - -/* - * Receive an AX.25 frame via a SLIP interface. - */ -int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype) -{ - skb->sk = NULL; /* Initially we don't know who it's for */ - skb->destructor = NULL; /* Who initializes this, dammit?! */ - - if ((*skb->data & 0x0F) != 0) { - kfree_skb(skb); /* Not a KISS data frame */ - return 0; - } - - skb_pull(skb, AX25_KISS_HEADER_LEN); /* Remove the KISS byte */ - - return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype); -} - |