diff options
Diffstat (limited to 'net/ax25/ax25_in.c')
-rw-r--r-- | net/ax25/ax25_in.c | 879 |
1 files changed, 282 insertions, 597 deletions
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 3ef1c3fdf..ec9ce4da0 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -1,10 +1,10 @@ /* - * AX.25 release 033 + * AX.25 release 036 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. * - * This code REQUIRES 1.2.1 or higher/ NET3.029 + * This code REQUIRES 2.1.15 or higher/ NET3.038 * * This module: * This module is free software; you can redistribute it and/or @@ -35,6 +35,9 @@ * 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. */ #include <linux/config.h> @@ -53,16 +56,16 @@ #include <linux/inet.h> #include <linux/netdevice.h> #include <linux/skbuff.h> +#include <linux/firewall.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> -static int ax25_rx_iframe(ax25_cb *, struct sk_buff *); - /* * Given a fragment, queue it on the fragment queue and if the fragment * is complete, send it back to ax25_rx_iframe. @@ -71,12 +74,12 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) { struct sk_buff *skbn, *skbo; int hdrlen, nhdrlen; - + if (ax25->fragno != 0) { - if (!(*skb->data & SEG_FIRST)) { - if ((ax25->fragno - 1) == (*skb->data & SEG_REM)) { + if (!(*skb->data & AX25_SEG_FIRST)) { + if ((ax25->fragno - 1) == (*skb->data & AX25_SEG_REM)) { /* Enqueue fragment */ - ax25->fragno = *skb->data & SEG_REM; + ax25->fragno = *skb->data & AX25_SEG_REM; skb_pull(skb, 1); /* skip fragno */ ax25->fraglen += skb->len; skb_queue_tail(&ax25->frag_queue, skb); @@ -89,14 +92,7 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) return 1; } - skbn->free = 1; - skbn->arp = 1; - skbn->dev = ax25->device; - - if (ax25->sk != NULL) { - skbn->sk = ax25->sk; - atomic_add(skbn->truesize, &ax25->sk->rmem_alloc); - } + skbn->dev = ax25->ax25_dev->dev; skb_reserve(skbn, AX25_MAX_HEADER_LEN); @@ -125,16 +121,16 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) if (ax25_rx_iframe(ax25, skbn) == 0) kfree_skb(skbn, FREE_READ); } - + return 1; } } } else { /* First fragment received */ - if (*skb->data & SEG_FIRST) { + if (*skb->data & AX25_SEG_FIRST) { while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) kfree_skb(skbo, FREE_READ); - ax25->fragno = *skb->data & SEG_REM; + ax25->fragno = *skb->data & AX25_SEG_REM; skb_pull(skb, 1); /* skip fragno */ ax25->fraglen = skb->len; skb_queue_tail(&ax25->frag_queue, skb); @@ -149,23 +145,36 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) * This is where all valid I frames are sent to, to be dispatched to * whichever protocol requires them. */ -static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) +int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) { int (*func)(struct sk_buff *, ax25_cb *); volatile int queued = 0; unsigned char pid; - + if (skb == NULL) return 0; ax25->idletimer = ax25->idle; - + pid = *skb->data; #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, FREE_READ); + skb = skbn; + } + skb_pull(skb, 1); /* Remove PID */ - skb->h.raw = skb->data; - ip_rcv(skb, ax25->device, NULL); /* Wrong ptype */ + skb->h.raw = skb->data; + skb->nh.raw = skb->data; + skb->dev = ax25->ax25_dev->dev; + skb->pkt_type = PACKET_HOST; + ip_rcv(skb, skb->dev, NULL); /* Wrong ptype */ return 1; } #endif @@ -178,643 +187,319 @@ static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) skb_pull(skb, 1); /* Remove PID */ return (*func)(skb, ax25); } - - if (ax25->sk != NULL && ax25_dev_get_value(ax25->device, AX25_VALUES_TEXT) && ax25->sk->protocol == pid) { + + if (ax25->sk != NULL && ax25->ax25_dev->values[AX25_VALUES_CONMODE] == 2 && ax25->sk->protocol == pid) { if (sock_queue_rcv_skb(ax25->sk, skb) == 0) queued = 1; else - ax25->condition |= OWN_RX_BUSY_CONDITION; + ax25->condition |= AX25_COND_OWN_RX_BUSY; } return queued; } /* - * State machine for state 1, Awaiting Connection State. - * The handling of the timer(s) is in file ax25_timer.c. - * Handling of state 0 and connection release is in ax25.c. + * Higher level upcall for a LAPB frame */ -static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type, int dama) +static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama) { - switch (frametype) { - case SABM: - ax25->modulus = MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - ax25_send_control(ax25, UA, pf, C_RESPONSE); - break; - - case SABME: - ax25->modulus = EMODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); - ax25_send_control(ax25, UA, pf, C_RESPONSE); - break; + int queued = 0; - case DISC: - ax25_send_control(ax25, DM, pf, C_RESPONSE); - break; + if (ax25->state == AX25_STATE_0) + return 0; - case UA: - if (pf || dama) { - if (dama) ax25_dama_on(ax25); /* bke */ - - ax25_calculate_rtt(ax25); - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - ax25->dama_slave = dama; /* bke */ - - if (ax25->sk != NULL) { - ax25->sk->state = TCP_ESTABLISHED; - /* For WAIT_SABM connections we will produce an accept ready socket here */ - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - } - } - break; + del_timer(&ax25->timer); - case DM: - if (pf) { - if (ax25->modulus == MODULUS) { - ax25_clear_queues(ax25); - ax25->state = AX25_STATE_0; - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ECONNREFUSED; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } else { - ax25->modulus = MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - } - } + 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; - default: - if (dama && pf) - ax25_send_control(ax25, SABM, POLLON, C_COMMAND); +#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 } - return 0; + ax25_set_timer(ax25); + + return queued; } -/* - * State machine for state 2, Awaiting Release State. - * The handling of the timer(s) is in file ax25_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) +static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_addr, struct packet_type *ptype) { - switch (frametype) { - case SABM: - case SABME: - ax25_send_control(ax25, DM, pf, C_RESPONSE); - if (ax25->dama_slave) - ax25_send_control(ax25, DISC, POLLON, C_COMMAND); - break; - - case DISC: - ax25_send_control(ax25, UA, pf, C_RESPONSE); - if (ax25->dama_slave) { - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } - break; + 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; + + /* + * Process the AX.25/LAPB frame. + */ + + skb->h.raw = skb->data; + + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { + kfree_skb(skb, FREE_READ); + return 0; + } - case UA: - if (pf) { - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } - break; + if (call_in_firewall(PF_AX25, skb->dev, skb->h.raw, NULL,&skb) != FW_ACCEPT) { + kfree_skb(skb, FREE_READ); + return 0; + } - case DM: - if (pf) { - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } - break; + /* + * Parse the address header. + */ - case I: - case REJ: - case RNR: - case RR: - if (pf) { - if (ax25->dama_slave) - ax25_send_control(ax25, DISC, POLLON, C_COMMAND); - else - ax25_send_control(ax25, DM, POLLON, C_RESPONSE); - } - break; - - default: - break; + if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) { + kfree_skb(skb, FREE_READ); + return 0; } - return 0; -} + /* + * Ours perhaps ? + */ + if (dp.lastrepeat + 1 < dp.ndigi) /* Not yet digipeated completely */ + next_digi = &dp.calls[dp.lastrepeat + 1]; -/* - * State machine for state 3, Connected State. - * The handling of the timer(s) is in file ax25_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type, int dama) -{ - int queued = 0; + /* + * Pull of the AX.25 headers leaving the CTRL/PID bytes + */ + skb_pull(skb, ax25_addr_size(&dp)); - switch (frametype) { - case SABM: - if (dama) ax25_dama_on(ax25); - ax25->modulus = MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - ax25_send_control(ax25, UA, pf, C_RESPONSE); - ax25->condition = 0x00; - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->dama_slave = dama; - break; + /* For our port addresses ? */ + if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi) + mine = 1; - case SABME: - if (dama) ax25_dama_on(ax25); - ax25->modulus = EMODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); - ax25_send_control(ax25, UA, pf, C_RESPONSE); - ax25->condition = 0x00; - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->dama_slave = dama; - break; + /* Also match on any registered callsign from L3/4 */ + if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi) + mine = 1; - case DISC: - ax25_clear_queues(ax25); - ax25_send_control(ax25, UA, pf, C_RESPONSE); - ax25->t3timer = 0; - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - break; + /* 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 */ - case DM: - ax25_clear_queues(ax25); - ax25->t3timer = 0; - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ECONNRESET; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - break; + if ((raw = ax25_addr_match(&dest)) != NULL) + ax25_send_to_raw(raw, skb, skb->data[1]); - case RNR: - ax25->condition |= PEER_RX_BUSY_CONDITION; - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_check_iframes_acked(ax25, nr); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case RR: - ax25->condition &= ~PEER_RX_BUSY_CONDITION; - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_check_iframes_acked(ax25, nr); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case REJ: - ax25->condition &= ~PEER_RX_BUSY_CONDITION; - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - ax25_calculate_rtt(ax25); - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25_requeue_frames(ax25); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case I: -#ifndef AX25_BROKEN_NETMAC - if (type != C_COMMAND) - break; -#endif - if (!ax25_validate_nr(ax25, nr)) { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; + if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { + kfree_skb(skb, FREE_READ); + 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; + ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ break; - } - if (ax25->condition & PEER_RX_BUSY_CONDITION) { - ax25_frames_acked(ax25, nr); - } else { - ax25_check_iframes_acked(ax25, nr); - } - if (ax25->condition & OWN_RX_BUSY_CONDITION) { - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } + + 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; + arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & OWN_RX_BUSY_CONDITION) { - ax25->vr = ns; /* ax25->vr - 1 */ - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } - break; - } - ax25->condition &= ~REJECT_CONDITION; - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } else { - if (!(ax25->condition & ACK_PENDING_CONDITION)) { - ax25->t2timer = ax25->t2; - ax25->condition |= ACK_PENDING_CONDITION; - } - } - } else { - if (ax25->condition & REJECT_CONDITION) { - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); +#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, FREE_READ); + } else { + /* + * Remove the control and PID. + */ + skb_pull(skb, 2); + if (sock_queue_rcv_skb(sk, skb) != 0) + kfree_skb(skb, FREE_READ); } } else { - ax25->condition |= REJECT_CONDITION; - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_send_control(ax25, REJ, pf, C_RESPONSE); - ax25->condition &= ~ACK_PENDING_CONDITION; + kfree_skb(skb, FREE_READ); } - } - break; + break; - case FRMR: - case ILLEGAL: - ax25_establish_data_link(ax25); - ax25->state = AX25_STATE_1; - break; + default: + kfree_skb(skb, FREE_READ); /* Will scan SOCK_AX25 RAW sockets */ + break; + } - default: - break; + return 0; } - return queued; -} + /* + * 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, FREE_READ); + return 0; + } -/* - * State machine for state 4, Timer Recovery State. - * The handling of the timer(s) is in file ax25_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type, int dama) -{ - int queued = 0; + /* LAPB */ - switch (frametype) { - case SABM: - if (dama) ax25_dama_on(ax25); - ax25->dama_slave = dama; - ax25->modulus = MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - ax25_send_control(ax25, UA, pf, C_RESPONSE); - ax25->condition = 0x00; - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - break; + /* AX.25 state 1-4 */ - case SABME: - if (dama) ax25_dama_on(ax25); - ax25->dama_slave = dama; - ax25->modulus = EMODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); - ax25_send_control(ax25, UA, pf, C_RESPONSE); - ax25->condition = 0x00; - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - break; + ax25_digi_invert(&dp, &reverse_dp); - case DISC: - ax25_clear_queues(ax25); - ax25_send_control(ax25, UA, pf, C_RESPONSE); - ax25->t3timer = 0; - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - break; + 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, FREE_READ); - case DM: - ax25_clear_queues(ax25); - ax25->t3timer = 0; - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ECONNRESET; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - break; + return 0; + } - case RNR: - ax25->condition |= PEER_RX_BUSY_CONDITION; - if (type == C_RESPONSE && pf) { - ax25->t1timer = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25->t3timer = ax25->t3; - ax25->n2count = 0; - ax25->state = AX25_STATE_3; - } - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case RR: - ax25->condition &= ~PEER_RX_BUSY_CONDITION; - if (pf && (type == C_RESPONSE || (ax25->dama_slave && type == C_COMMAND))) { - ax25->t1timer = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25->t3timer = ax25->t3; - ax25->n2count = 0; - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } + /* AX.25 state 0 (disconnected) */ - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; + /* a) received not a SABM(E) */ - case REJ: - ax25->condition &= ~PEER_RX_BUSY_CONDITION; - if (pf && (type == C_RESPONSE || (ax25->dama_slave && type == C_COMMAND))) { - ax25->t1timer = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25->t3timer = ax25->t3; - ax25->n2count = 0; - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if(ax25->vs != ax25->va) { - ax25_requeue_frames(ax25); - } - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; + 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. + */ + if ((*skb->data & ~AX25_PF) != AX25_DM && mine) + ax25_return_dm(dev, &src, &dest, &dp); - case I: -#ifndef AX25_BROKEN_NETMAC - if (type != C_COMMAND) - break; + kfree_skb(skb, FREE_READ); + 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); + + if (sk != NULL) { + if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) { + if (mine) ax25_return_dm(dev, &src, &dest, &dp); + kfree_skb(skb, FREE_READ); + return 0; + } + + ax25 = make->protinfo.ax25; + + skb_queue_head(&sk->receive_queue, skb); + + skb->sk = make; + make->state = TCP_ESTABLISHED; + make->pair = sk; + + sk->ack_backlog++; + } else { + if (!mine) { + kfree_skb(skb, FREE_READ); + return 0; + } + + if ((ax25 = ax25_create_cb()) == NULL) { + ax25_return_dm(dev, &src, &dest, &dp); + kfree_skb(skb, FREE_READ); + return 0; + } + + ax25_fillin_cb(ax25, ax25_dev); + ax25->idletimer = ax25->idle; + } + + ax25->source_addr = dest; + ax25->dest_addr = src; + + /* + * Sort out any digipeated paths. + */ + if (dp.ndigi != 0 && ax25->digipeat == NULL && (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + kfree_skb(skb, FREE_READ); + ax25_destroy_socket(ax25); + return 0; + } + + if (dp.ndigi == 0) { + if (ax25->digipeat != NULL) { + kfree_s(ax25->digipeat, sizeof(ax25_digi)); + ax25->digipeat = NULL; + } + } else { + /* Reverse the source SABM's path */ + *ax25->digipeat = reverse_dp; + } + + 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); + +#ifdef CONFIG_AX25_DAMA_SLAVE + if (dama && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) + ax25_dama_on(ax25); #endif - if (!ax25_validate_nr(ax25, nr)) { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } - ax25_frames_acked(ax25, nr); - if (ax25->condition & OWN_RX_BUSY_CONDITION) { - if (pf) { - if (ax25->dama_slave) - ax25_enquiry_response(ax25); - else - dama_enquiry_response(ax25); - } - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & OWN_RX_BUSY_CONDITION) { - ax25->vr = ns; /* ax25->vr - 1 */ - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } - break; - } - ax25->condition &= ~REJECT_CONDITION; - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } else { - if (!(ax25->condition & ACK_PENDING_CONDITION)) { - ax25->t2timer = ax25->t2; - ax25->condition |= ACK_PENDING_CONDITION; - } - } - } else { - if (ax25->condition & REJECT_CONDITION) { - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } - } else { - ax25->condition |= REJECT_CONDITION; - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_send_control(ax25, REJ, pf, C_RESPONSE); - ax25->condition &= ~ACK_PENDING_CONDITION; - } - } - break; - - case FRMR: - case ILLEGAL: - ax25_establish_data_link(ax25); - ax25->state = AX25_STATE_1; - break; - default: - break; + ax25->t3timer = ax25->t3; + ax25->state = AX25_STATE_3; + + ax25_insert_socket(ax25); + + ax25_set_timer(ax25); + + if (sk != NULL) { + if (!sk->dead) + sk->data_ready(sk, skb->len); + } else { + kfree_skb(skb, FREE_READ); } - return queued; + return 0; } /* - * Higher level upcall for a LAPB frame + * Receive an AX.25 frame via a SLIP interface. */ -int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama) +int ax25_kiss_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) { - int queued = 0, frametype, ns, nr, pf; - - if (ax25->state == AX25_STATE_0) - return 0; - - del_timer(&ax25->timer); - - frametype = ax25_decode(ax25, skb, &ns, &nr, &pf); + skb->sk = NULL; /* Initially we don't know who it's for */ - switch (ax25->state) { - case AX25_STATE_1: - queued = ax25_state1_machine(ax25, skb, frametype, pf, type, dama); - break; - case AX25_STATE_2: - queued = ax25_state2_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_3: - queued = ax25_state3_machine(ax25, skb, frametype, ns, nr, pf, type, dama); - break; - case AX25_STATE_4: - queued = ax25_state4_machine(ax25, skb, frametype, ns, nr, pf, type, dama); - break; + if ((*skb->data & 0x0F) != 0) { + kfree_skb(skb, FREE_READ); /* Not a KISS data frame */ + return 0; } - ax25_set_timer(ax25); + skb_pull(skb, AX25_KISS_HEADER_LEN); /* Remove the KISS byte */ - return queued; + return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype); } #endif |