diff options
Diffstat (limited to 'net/netrom')
-rw-r--r-- | net/netrom/af_netrom.c | 184 | ||||
-rw-r--r-- | net/netrom/nr_dev.c | 2 | ||||
-rw-r--r-- | net/netrom/nr_in.c | 60 | ||||
-rw-r--r-- | net/netrom/nr_out.c | 104 | ||||
-rw-r--r-- | net/netrom/nr_route.c | 27 | ||||
-rw-r--r-- | net/netrom/nr_subr.c | 26 | ||||
-rw-r--r-- | net/netrom/nr_timer.c | 208 | ||||
-rw-r--r-- | net/netrom/sysctl_net_netrom.c | 16 |
8 files changed, 354 insertions, 273 deletions
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 22e1afbee..dd80a211b 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1,5 +1,5 @@ /* - * NET/ROM release 006 + * NET/ROM release 007 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -28,6 +28,8 @@ * Alan(GW4PTS) Started POSIXisms * NET/ROM 006 Alan(GW4PTS) Brought in line with the ANK changes * Jonathan(G4KLX) Removed hdrincl. + * NET/ROM 007 Jonathan(G4KLX) New timer architecture. + * Impmented Idle timer. */ #include <linux/config.h> @@ -122,8 +124,7 @@ static void nr_remove_socket(struct sock *sk) struct sock *s; unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); cli(); if ((s = nr_list) == sk) { nr_list = s->next; @@ -152,15 +153,8 @@ static void nr_kill_by_device(struct device *dev) struct sock *s; for (s = nr_list; s != NULL; s = s->next) { - if (s->protinfo.nr->device == dev) { - s->protinfo.nr->state = NR_STATE_0; - s->protinfo.nr->device = NULL; - s->state = TCP_CLOSE; - s->err = ENETUNREACH; - s->shutdown |= SEND_SHUTDOWN; - s->state_change(s); - s->dead = 1; - } + if (s->protinfo.nr->device == dev) + nr_disconnect(s, ENETUNREACH); } } @@ -187,8 +181,7 @@ static void nr_insert_socket(struct sock *sk) { unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); cli(); sk->next = nr_list; nr_list = sk; @@ -289,10 +282,13 @@ void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer struct sk_buff *skb; unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); cli(); - del_timer(&sk->timer); + nr_stop_heartbeat(sk); + nr_stop_t1timer(sk); + nr_stop_t2timer(sk); + nr_stop_t4timer(sk); + nr_stop_idletimer(sk); nr_remove_socket(sk); nr_clear_queues(sk); /* Flush the queues */ @@ -300,7 +296,7 @@ void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { if (skb->sk != sk) { /* A pending connection */ skb->sk->dead = 1; /* Queue the unaccepted socket for death */ - nr_set_timer(skb->sk); + nr_start_heartbeat(skb->sk); skb->sk->protinfo.nr->state = NR_STATE_0; } @@ -345,13 +341,13 @@ static int nr_setsockopt(struct socket *sock, int level, int optname, case NETROM_T1: if (opt < 1) return -EINVAL; - sk->protinfo.nr->t1 = opt * NR_SLOWHZ; + sk->protinfo.nr->t1 = opt * HZ; return 0; case NETROM_T2: if (opt < 1) return -EINVAL; - sk->protinfo.nr->t2 = opt * NR_SLOWHZ; + sk->protinfo.nr->t2 = opt * HZ; return 0; case NETROM_N2: @@ -363,13 +359,13 @@ static int nr_setsockopt(struct socket *sock, int level, int optname, case NETROM_T4: if (opt < 1) return -EINVAL; - sk->protinfo.nr->t4 = opt * NR_SLOWHZ; + sk->protinfo.nr->t4 = opt * HZ; return 0; case NETROM_IDLE: - if (opt < 1) + if (opt < 0) return -EINVAL; - sk->protinfo.nr->idle = opt * 60 * NR_SLOWHZ; + sk->protinfo.nr->idle = opt * 60 * HZ; return 0; default: @@ -392,11 +388,11 @@ static int nr_getsockopt(struct socket *sock, int level, int optname, switch (optname) { case NETROM_T1: - val = (sk->protinfo.nr->t1 * 2) / NR_SLOWHZ; + val = sk->protinfo.nr->t1 / HZ; break; case NETROM_T2: - val = sk->protinfo.nr->t2 / NR_SLOWHZ; + val = sk->protinfo.nr->t2 / HZ; break; case NETROM_N2: @@ -404,11 +400,11 @@ static int nr_getsockopt(struct socket *sock, int level, int optname, break; case NETROM_T4: - val = sk->protinfo.nr->t4 / NR_SLOWHZ; + val = sk->protinfo.nr->t4 / HZ; break; case NETROM_IDLE: - val = sk->protinfo.nr->idle / (NR_SLOWHZ * 60); + val = sk->protinfo.nr->idle / (60 * HZ); break; default: @@ -463,6 +459,11 @@ static int nr_create(struct socket *sock, int protocol) skb_queue_head_init(&nr->reseq_queue); skb_queue_head_init(&nr->frag_queue); + init_timer(&nr->t1timer); + init_timer(&nr->t2timer); + init_timer(&nr->t4timer); + init_timer(&nr->idletimer); + nr->t1 = sysctl_netrom_transport_timeout; nr->t2 = sysctl_netrom_transport_acknowledge_delay; nr->n2 = sysctl_netrom_transport_maximum_tries; @@ -507,6 +508,11 @@ static struct sock *nr_make_new(struct sock *osk) skb_queue_head_init(&nr->reseq_queue); skb_queue_head_init(&nr->frag_queue); + init_timer(&nr->t1timer); + init_timer(&nr->t2timer); + init_timer(&nr->t4timer); + init_timer(&nr->idletimer); + nr->t1 = osk->protinfo.nr->t1; nr->t2 = osk->protinfo.nr->t2; nr->n2 = osk->protinfo.nr->n2; @@ -539,39 +545,20 @@ static int nr_release(struct socket *sock, struct socket *peer) switch (sk->protinfo.nr->state) { case NR_STATE_0: - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; + case NR_STATE_2: + nr_disconnect(sk, 0); nr_destroy_socket(sk); break; case NR_STATE_1: - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - nr_destroy_socket(sk); - break; - - case NR_STATE_2: - nr_write_internal(sk, NR_DISCACK); - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - nr_destroy_socket(sk); - break; - case NR_STATE_3: nr_clear_queues(sk); sk->protinfo.nr->n2count = 0; nr_write_internal(sk, NR_DISCREQ); - sk->protinfo.nr->t1timer = sk->protinfo.nr->t1; - sk->protinfo.nr->t2timer = 0; - sk->protinfo.nr->t4timer = 0; + nr_start_t1timer(sk); + nr_stop_t2timer(sk); + nr_stop_t4timer(sk); + nr_stop_idletimer(sk); sk->protinfo.nr->state = NR_STATE_2; sk->state = TCP_CLOSE; sk->shutdown |= SEND_SHUTDOWN; @@ -704,9 +691,12 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr, /* Move to connecting socket, start sending Connect Requests */ sock->state = SS_CONNECTING; sk->state = TCP_SYN_SENT; + nr_establish_data_link(sk); + sk->protinfo.nr->state = NR_STATE_1; - nr_set_timer(sk); + + nr_start_heartbeat(sk); /* Now the loop */ if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) @@ -838,13 +828,13 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev) circuit_index = skb->data[15]; circuit_id = skb->data[16]; - frametype = skb->data[19]; + frametype = skb->data[19] & 0x0F; #ifdef CONFIG_INET /* * Check for an incoming IP over NET/ROM frame. */ - if ((frametype & 0x0F) == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) { + if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) { skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); skb->h.raw = skb->data; @@ -856,11 +846,11 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev) * Find an existing socket connection, based on circuit ID, if it's * a Connect Request base it on their circuit ID. */ - if (((frametype & 0x0F) != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) || - ((frametype & 0x0F) == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id)) != NULL)) { + if ((frametype != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) || + (frametype == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id)) != NULL)) { skb->h.raw = skb->data; - if ((frametype & 0x0F) == NR_CONNACK && skb->len == 22) + if (frametype == NR_CONNACK && skb->len == 22) sk->protinfo.nr->bpqext = 1; else sk->protinfo.nr->bpqext = 0; @@ -868,8 +858,16 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev) return nr_process_rx_frame(sk, skb); } - if ((frametype & 0x0F) != NR_CONNREQ) - return 0; + switch (frametype) { + case NR_CONNREQ: + break; + case NR_DISCREQ: + case NR_DISCACK: + return 0; + default: + nr_transmit_dm(skb); + return 0; + } sk = nr_find_listener(dest); @@ -905,8 +903,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev) /* L4 timeout negotiation */ if (skb->len == 37) { timeout = skb->data[36] * 256 + skb->data[35]; - if (timeout * NR_SLOWHZ < make->protinfo.nr->t1) - make->protinfo.nr->t1 = timeout * NR_SLOWHZ; + if (timeout * HZ < make->protinfo.nr->t1) + make->protinfo.nr->t1 = timeout * HZ; make->protinfo.nr->bpqext = 1; } else { make->protinfo.nr->bpqext = 0; @@ -927,7 +925,8 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev) skb_queue_head(&sk->receive_queue, skb); - nr_set_timer(make); + nr_start_heartbeat(make); + nr_start_idletimer(make); if (!sk->dead) sk->data_ready(sk, skb->len); @@ -973,6 +972,7 @@ static int nr_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct s sax.sax25_family = AF_NETROM; sax.sax25_call = sk->protinfo.nr->dest_addr; } + SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n"); /* Build a packet */ @@ -1074,37 +1074,35 @@ static int nr_shutdown(struct socket *sk, int how) static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - int err; - long amount = 0; switch (cmd) { - case TIOCOUTQ: - if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0) - return err; + case TIOCOUTQ: { + long amount; amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; - put_user(amount, (int *)arg); + if (put_user(amount, (int *)arg)) + return -EFAULT; return 0; + } case TIOCINQ: { struct sk_buff *skb; + long amount = 0L; /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->receive_queue)) != NULL) - amount = skb->len - 20; - if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0) - return err; - put_user(amount, (int *)arg); + amount = skb->len; + if (put_user(amount, (int *)arg)) + return -EFAULT; return 0; } case SIOCGSTAMP: if (sk != NULL) { - if (sk->stamp.tv_sec==0) + if (sk->stamp.tv_sec == 0) return -ENOENT; - if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0) - return err; - copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)); + if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) + return -EFAULT; return 0; } return -EINVAL; @@ -1146,7 +1144,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int cli(); - len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 n2 wnd Snd-Q Rcv-Q\n"); + len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q\n"); for (s = nr_list; s != NULL; s = s->next) { if ((dev = s->protinfo.nr->device) == NULL) @@ -1158,20 +1156,30 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length, int ax2asc(&s->protinfo.nr->user_addr)); len += sprintf(buffer + len, "%-9s ", ax2asc(&s->protinfo.nr->dest_addr)); - len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %5d %5d\n", + len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d\n", ax2asc(&s->protinfo.nr->source_addr), - devname, s->protinfo.nr->my_index, s->protinfo.nr->my_id, - s->protinfo.nr->your_index, s->protinfo.nr->your_id, + devname, + s->protinfo.nr->my_index, + s->protinfo.nr->my_id, + s->protinfo.nr->your_index, + s->protinfo.nr->your_id, s->protinfo.nr->state, - s->protinfo.nr->vs, s->protinfo.nr->vr, s->protinfo.nr->va, - s->protinfo.nr->t1timer / NR_SLOWHZ, - s->protinfo.nr->t1 / NR_SLOWHZ, - s->protinfo.nr->t2timer / NR_SLOWHZ, - s->protinfo.nr->t2 / NR_SLOWHZ, + s->protinfo.nr->vs, + s->protinfo.nr->vr, + s->protinfo.nr->va, + ax25_display_timer(&s->protinfo.nr->t1timer) / HZ, + s->protinfo.nr->t1 / HZ, + ax25_display_timer(&s->protinfo.nr->t2timer) / HZ, + s->protinfo.nr->t2 / HZ, + ax25_display_timer(&s->protinfo.nr->t4timer) / HZ, + s->protinfo.nr->t4 / HZ, + ax25_display_timer(&s->protinfo.nr->idletimer) / (60 * HZ), + s->protinfo.nr->idle / (60 * HZ), s->protinfo.nr->n2count, s->protinfo.nr->n2, s->protinfo.nr->window, - atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc)); + atomic_read(&s->wmem_alloc), + atomic_read(&s->rmem_alloc)); pos = begin + len; @@ -1269,7 +1277,7 @@ __initfunc(void nr_proto_init(struct net_proto *pro)) sock_register(&nr_family_ops); register_netdevice_notifier(&nr_dev_notifier); - printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.6 for AX25.035 Linux 2.1\n"); + printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.1\n"); ax25_protocol_register(AX25_P_NETROM, nr_route_frame); ax25_linkfail_register(nr_link_failed); diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c index 2d88bec2b..f7b617dcc 100644 --- a/net/netrom/nr_dev.c +++ b/net/netrom/nr_dev.c @@ -1,5 +1,5 @@ /* - * NET/ROM release 006 + * NET/ROM release 007 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c index c13e92666..a0d3148c2 100644 --- a/net/netrom/nr_in.c +++ b/net/netrom/nr_in.c @@ -1,5 +1,5 @@ /* - * NET/ROM release 006 + * NET/ROM release 007 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -21,6 +21,7 @@ * Darryl(G7LED) Added missing INFO with NAK case, optimized * INFOACK handling, removed reconnect on error. * NET/ROM 006 Jonathan(G4KLX) Hdrincl removal changes. + * NET/ROM 007 Jonathan(G4KLX) New timer architecture. */ #include <linux/config.h> @@ -54,6 +55,8 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); + nr_start_idletimer(sk); + if (more) { sk->protinfo.nr->fraglen += skb->len; skb_queue_tail(&sk->protinfo.nr->frag_queue, skb); @@ -90,11 +93,10 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype switch (frametype) { case NR_CONNACK: + nr_stop_t1timer(sk); + nr_start_idletimer(sk); sk->protinfo.nr->your_index = skb->data[17]; sk->protinfo.nr->your_id = skb->data[18]; - sk->protinfo.nr->t1timer = 0; - sk->protinfo.nr->t2timer = 0; - sk->protinfo.nr->t4timer = 0; sk->protinfo.nr->vs = 0; sk->protinfo.nr->va = 0; sk->protinfo.nr->vr = 0; @@ -103,20 +105,12 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype sk->protinfo.nr->n2count = 0; sk->protinfo.nr->window = skb->data[20]; sk->state = TCP_ESTABLISHED; - /* For WAIT_SABM connections we will produce an accept ready socket here */ if (!sk->dead) sk->state_change(sk); break; case NR_CONNACK | NR_CHOKE_FLAG: - nr_clear_queues(sk); - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->err = ECONNREFUSED; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + nr_disconnect(sk, ECONNREFUSED); break; default: @@ -139,13 +133,7 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype nr_write_internal(sk, NR_DISCACK); case NR_DISCACK: - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->err = 0; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + nr_disconnect(sk, 0); break; default: @@ -178,26 +166,12 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype break; case NR_DISCREQ: - nr_clear_queues(sk); nr_write_internal(sk, NR_DISCACK); - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->err = 0; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + nr_disconnect(sk, 0); break; case NR_DISCACK: - nr_clear_queues(sk); - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->err = ECONNRESET; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + nr_disconnect(sk, ECONNRESET); break; case NR_INFOACK: @@ -206,10 +180,10 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG: if (frametype & NR_CHOKE_FLAG) { sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY; - sk->protinfo.nr->t4timer = sk->protinfo.nr->t4; + nr_start_t4timer(sk); } else { sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY; - sk->protinfo.nr->t4timer = 0; + nr_stop_t4timer(sk); } if (!nr_validate_nr(sk, nr)) { break; @@ -236,10 +210,10 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG: if (frametype & NR_CHOKE_FLAG) { sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY; - sk->protinfo.nr->t4timer = sk->protinfo.nr->t4; + nr_start_t4timer(sk); } else { sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY; - sk->protinfo.nr->t4timer = 0; + nr_stop_t4timer(sk); } if (nr_validate_nr(sk, nr)) { if (frametype & NR_NAK_FLAG) { @@ -286,8 +260,8 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype nr_enquiry_response(sk); } else { if (!(sk->protinfo.nr->condition & NR_COND_ACK_PENDING)) { - sk->protinfo.nr->t2timer = sk->protinfo.nr->t2; sk->protinfo.nr->condition |= NR_COND_ACK_PENDING; + nr_start_t2timer(sk); } } break; @@ -307,8 +281,6 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb) if (sk->protinfo.nr->state == NR_STATE_0) return 0; - del_timer(&sk->timer); - frametype = skb->data[19]; switch (sk->protinfo.nr->state) { @@ -323,7 +295,7 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb) break; } - nr_set_timer(sk); + nr_kick(sk); return queued; } diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c index 7c053b482..4c3eb61d8 100644 --- a/net/netrom/nr_out.c +++ b/net/netrom/nr_out.c @@ -1,5 +1,5 @@ /* - * NET/ROM release 006 + * NET/ROM release 007 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -13,6 +13,7 @@ * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_out.c * NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragmentation. * Darryl(G7LED) Fixed NAK, to give out correct reponse. + * NET/ROM 007 Jonathan(G4KLX) New timer architecture. */ #include <linux/config.h> @@ -83,8 +84,7 @@ void nr_output(struct sock *sk, struct sk_buff *skb) skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */ } - if (sk->protinfo.nr->state == NR_STATE_3) - nr_kick(sk); + nr_kick(sk); } /* @@ -102,6 +102,8 @@ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb) if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY) skb->data[4] |= NR_CHOKE_FLAG; + nr_start_idletimer(sk); + nr_transmit_buffer(sk, skb); } @@ -125,7 +127,8 @@ void nr_send_nak_frame(struct sock *sk) sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING; sk->protinfo.nr->vl = sk->protinfo.nr->vr; - sk->protinfo.nr->t1timer = 0; + + nr_stop_t1timer(sk); } void nr_kick(struct sock *sk) @@ -133,57 +136,60 @@ void nr_kick(struct sock *sk) struct sk_buff *skb, *skbn; unsigned short start, end; - del_timer(&sk->timer); + if (sk->protinfo.nr->state != NR_STATE_3) + return; + + if (sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY) + return; + + if (skb_peek(&sk->write_queue) == NULL) + return; start = (skb_peek(&sk->protinfo.nr->ack_queue) == NULL) ? sk->protinfo.nr->va : sk->protinfo.nr->vs; end = (sk->protinfo.nr->va + sk->protinfo.nr->window) % NR_MODULUS; - if (!(sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY) && - start != end && - skb_peek(&sk->write_queue) != NULL) { - - sk->protinfo.nr->vs = start; + if (start == end) + return; - /* - * Transmit data until either we're out of data to send or - * the window is full. - */ + sk->protinfo.nr->vs = start; - /* - * Dequeue the frame and copy it. - */ - skb = skb_dequeue(&sk->write_queue); + /* + * Transmit data until either we're out of data to send or + * the window is full. + */ - do { - if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { - skb_queue_head(&sk->write_queue, skb); - break; - } + /* + * Dequeue the frame and copy it. + */ + skb = skb_dequeue(&sk->write_queue); - skb_set_owner_w(skbn, sk); + do { + if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { + skb_queue_head(&sk->write_queue, skb); + break; + } - /* - * Transmit the frame copy. - */ - nr_send_iframe(sk, skbn); + skb_set_owner_w(skbn, sk); - sk->protinfo.nr->vs = (sk->protinfo.nr->vs + 1) % NR_MODULUS; + /* + * Transmit the frame copy. + */ + nr_send_iframe(sk, skbn); - /* - * Requeue the original data frame. - */ - skb_queue_tail(&sk->protinfo.nr->ack_queue, skb); + sk->protinfo.nr->vs = (sk->protinfo.nr->vs + 1) % NR_MODULUS; - } while (sk->protinfo.nr->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL); + /* + * Requeue the original data frame. + */ + skb_queue_tail(&sk->protinfo.nr->ack_queue, skb); - sk->protinfo.nr->vl = sk->protinfo.nr->vr; - sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING; + } while (sk->protinfo.nr->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL); - if (sk->protinfo.nr->t1timer == 0) - sk->protinfo.nr->t1timer = sk->protinfo.nr->t1; - } + sk->protinfo.nr->vl = sk->protinfo.nr->vr; + sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING; - nr_set_timer(sk); + if (!nr_t1timer_running(sk)) + nr_start_t1timer(sk); } void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb) @@ -211,13 +217,7 @@ void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb) if (!nr_route_frame(skb, NULL)) { kfree_skb(skb, FREE_WRITE); - - sk->state = TCP_CLOSE; - sk->err = ENETUNREACH; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + nr_disconnect(sk, ENETUNREACH); } } @@ -233,8 +233,10 @@ void nr_establish_data_link(struct sock *sk) nr_write_internal(sk, NR_CONNREQ); - sk->protinfo.nr->t2timer = 0; - sk->protinfo.nr->t1timer = sk->protinfo.nr->t1; + nr_stop_t2timer(sk); + nr_stop_t4timer(sk); + nr_stop_idletimer(sk); + nr_start_t1timer(sk); } /* @@ -261,12 +263,12 @@ void nr_check_iframes_acked(struct sock *sk, unsigned short nr) { if (sk->protinfo.nr->vs == nr) { nr_frames_acked(sk, nr); - sk->protinfo.nr->t1timer = 0; + nr_stop_t1timer(sk); sk->protinfo.nr->n2count = 0; } else { if (sk->protinfo.nr->va != nr) { nr_frames_acked(sk, nr); - sk->protinfo.nr->t1timer = sk->protinfo.nr->t1; + nr_start_t1timer(sk); } } } diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index 41399a53c..ffbb240c4 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c @@ -1,5 +1,5 @@ /* - * NET/ROM release 006 + * NET/ROM release 007 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -93,6 +93,7 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2 nr_neigh->callsign = *ax25; nr_neigh->digipeat = NULL; + nr_neigh->ax25 = NULL; nr_neigh->dev = dev; nr_neigh->quality = sysctl_netrom_default_path_quality; nr_neigh->locked = 0; @@ -372,6 +373,7 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct dev nr_neigh->callsign = *callsign; nr_neigh->digipeat = NULL; + nr_neigh->ax25 = NULL; nr_neigh->dev = dev; nr_neigh->quality = quality; nr_neigh->locked = 1; @@ -582,7 +584,7 @@ static ax25_digi *nr_call_to_digi(int ndigis, ax25_address *digipeaters) } ax25_digi.ndigi = ndigis; - ax25_digi.lastrepeat = 0; + ax25_digi.lastrepeat = -1; return &ax25_digi; } @@ -594,14 +596,12 @@ int nr_rt_ioctl(unsigned int cmd, void *arg) { struct nr_route_struct nr_route; struct device *dev; - int err; switch (cmd) { case SIOCADDRT: - if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0) - return err; - copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)); + if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) + return -EFAULT; if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) return -EINVAL; if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) @@ -623,9 +623,8 @@ int nr_rt_ioctl(unsigned int cmd, void *arg) } case SIOCDELRT: - if ((err = verify_area(VERIFY_READ, arg, sizeof(struct nr_route_struct))) != 0) - return err; - copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)); + if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) + return -EFAULT; if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) return -EINVAL; switch (nr_route.type) { @@ -653,17 +652,19 @@ int nr_rt_ioctl(unsigned int cmd, void *arg) * A level 2 link has timed out, therefore it appears to be a poor link, * then don't use that neighbour until it is reset. */ -void nr_link_failed(ax25_address *callsign, struct device *dev) +void nr_link_failed(ax25_cb *ax25, int reason) { struct nr_neigh *nr_neigh; struct nr_node *nr_node; for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (ax25cmp(&nr_neigh->callsign, callsign) == 0 && nr_neigh->dev == dev) + if (nr_neigh->ax25 == ax25) break; if (nr_neigh == NULL) return; + nr_neigh->ax25 = NULL; + if (++nr_neigh->failed < sysctl_netrom_link_fails_count) return; for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) @@ -724,7 +725,9 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) dptr = skb_push(skb, 1); *dptr = AX25_P_NETROM; - return ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); + nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); + + return (nr_neigh->ax25 != NULL); } int nr_nodes_get_info(char *buffer, char **start, off_t offset, diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c index 5eae25279..d31141876 100644 --- a/net/netrom/nr_subr.c +++ b/net/netrom/nr_subr.c @@ -1,5 +1,5 @@ /* - * NET/ROM release 006 + * NET/ROM release 007 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -12,6 +12,7 @@ * History * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_subr.c * NET/ROM 003 Jonathan(G4KLX) Added G8BPQ NET/ROM extensions. + * NET/ROM 007 Jonathan(G4KLX) New timer architecture. */ #include <linux/config.h> @@ -172,7 +173,7 @@ void nr_write_internal(struct sock *sk, int frametype) switch (frametype & 0x0F) { case NR_CONNREQ: - timeout = sk->protinfo.nr->t1 / NR_SLOWHZ; + timeout = sk->protinfo.nr->t1 / HZ; *dptr++ = sk->protinfo.nr->my_index; *dptr++ = sk->protinfo.nr->my_id; *dptr++ = 0; @@ -268,4 +269,25 @@ void nr_transmit_dm(struct sk_buff *skb) kfree_skb(skbn, FREE_WRITE); } +void nr_disconnect(struct sock *sk, int reason) +{ + nr_stop_t1timer(sk); + nr_stop_t2timer(sk); + nr_stop_t4timer(sk); + nr_stop_idletimer(sk); + + nr_clear_queues(sk); + + sk->protinfo.nr->state = NR_STATE_0; + + sk->state = TCP_CLOSE; + sk->err = reason; + sk->shutdown |= SEND_SHUTDOWN; + + if (!sk->dead) + sk->state_change(sk); + + sk->dead = 1; +} + #endif diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c index cc96f26dd..b3fbd012e 100644 --- a/net/netrom/nr_timer.c +++ b/net/netrom/nr_timer.c @@ -1,5 +1,5 @@ /* - * NET/ROM release 006 + * NET/ROM release 007 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -11,6 +11,8 @@ * * History * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_timer.c + * NET/ROM 007 Jonathan(G4KLX) New timer architecture. + * Implemented idle timer. */ #include <linux/config.h> @@ -37,42 +39,110 @@ #include <linux/interrupt.h> #include <net/netrom.h> -static void nr_timer(unsigned long); +static void nr_heartbeat_expiry(unsigned long); +static void nr_t1timer_expiry(unsigned long); +static void nr_t2timer_expiry(unsigned long); +static void nr_t4timer_expiry(unsigned long); +static void nr_idletimer_expiry(unsigned long); -/* - * Linux set timer - */ -void nr_set_timer(struct sock *sk) +void nr_start_t1timer(struct sock *sk) +{ + del_timer(&sk->protinfo.nr->t1timer); + + sk->protinfo.nr->t1timer.data = (unsigned long)sk; + sk->protinfo.nr->t1timer.function = &nr_t1timer_expiry; + sk->protinfo.nr->t1timer.expires = jiffies + sk->protinfo.nr->t1; + + add_timer(&sk->protinfo.nr->t1timer); +} + +void nr_start_t2timer(struct sock *sk) +{ + del_timer(&sk->protinfo.nr->t2timer); + + sk->protinfo.nr->t2timer.data = (unsigned long)sk; + sk->protinfo.nr->t2timer.function = &nr_t2timer_expiry; + sk->protinfo.nr->t2timer.expires = jiffies + sk->protinfo.nr->t2; + + add_timer(&sk->protinfo.nr->t2timer); +} + +void nr_start_t4timer(struct sock *sk) +{ + del_timer(&sk->protinfo.nr->t4timer); + + sk->protinfo.nr->t4timer.data = (unsigned long)sk; + sk->protinfo.nr->t4timer.function = &nr_t4timer_expiry; + sk->protinfo.nr->t4timer.expires = jiffies + sk->protinfo.nr->t4; + + add_timer(&sk->protinfo.nr->t4timer); +} + +void nr_start_idletimer(struct sock *sk) { - unsigned long flags; + del_timer(&sk->protinfo.nr->idletimer); + + if (sk->protinfo.nr->idle > 0) { + sk->protinfo.nr->idletimer.data = (unsigned long)sk; + sk->protinfo.nr->idletimer.function = &nr_idletimer_expiry; + sk->protinfo.nr->idletimer.expires = jiffies + sk->protinfo.nr->idle; + + add_timer(&sk->protinfo.nr->idletimer); + } +} - save_flags(flags); cli(); +void nr_start_heartbeat(struct sock *sk) +{ del_timer(&sk->timer); - restore_flags(flags); sk->timer.data = (unsigned long)sk; - sk->timer.function = &nr_timer; - sk->timer.expires = jiffies + (HZ / 10); + sk->timer.function = &nr_heartbeat_expiry; + sk->timer.expires = jiffies + 5 * HZ; add_timer(&sk->timer); } -/* - * NET/ROM TIMER - * - * This routine is called every 100ms. Decrement timer by this - * amount - if expired then process the event. - */ -static void nr_timer(unsigned long param) +void nr_stop_t1timer(struct sock *sk) +{ + del_timer(&sk->protinfo.nr->t1timer); +} + +void nr_stop_t2timer(struct sock *sk) +{ + del_timer(&sk->protinfo.nr->t2timer); +} + +void nr_stop_t4timer(struct sock *sk) +{ + del_timer(&sk->protinfo.nr->t4timer); +} + +void nr_stop_idletimer(struct sock *sk) +{ + del_timer(&sk->protinfo.nr->idletimer); +} + +void nr_stop_heartbeat(struct sock *sk) +{ + del_timer(&sk->timer); +} + +int nr_t1timer_running(struct sock *sk) +{ + return (sk->protinfo.nr->t1timer.prev != NULL || + sk->protinfo.nr->t1timer.next != NULL); +} + +static void nr_heartbeat_expiry(unsigned long param) { struct sock *sk = (struct sock *)param; switch (sk->protinfo.nr->state) { + case NR_STATE_0: /* Magic here: If we listen() and a new link dies before it is accepted() it isn't 'dead' so doesn't get removed. */ if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) { - del_timer(&sk->timer); nr_destroy_socket(sk); return; } @@ -90,45 +160,63 @@ static void nr_timer(unsigned long param) nr_write_internal(sk, NR_INFOACK); break; } - /* - * Check for frames to transmit. - */ - nr_kick(sk); - break; - - default: break; } - if (sk->protinfo.nr->t2timer > 0 && --sk->protinfo.nr->t2timer == 0) { - if (sk->protinfo.nr->state == NR_STATE_3) { - if (sk->protinfo.nr->condition & NR_COND_ACK_PENDING) { - sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING; - nr_enquiry_response(sk); - } - } - } + nr_start_heartbeat(sk); +} - if (sk->protinfo.nr->t4timer > 0 && --sk->protinfo.nr->t4timer == 0) { - sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY; - } +static void nr_t2timer_expiry(unsigned long param) +{ + struct sock *sk = (struct sock *)param; - if (sk->protinfo.nr->t1timer == 0 || --sk->protinfo.nr->t1timer > 0) { - nr_set_timer(sk); - return; + if (sk->protinfo.nr->condition & NR_COND_ACK_PENDING) { + sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING; + nr_enquiry_response(sk); } +} + +static void nr_t4timer_expiry(unsigned long param) +{ + struct sock *sk = (struct sock *)param; + + sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY; +} + +static void nr_idletimer_expiry(unsigned long param) +{ + struct sock *sk = (struct sock *)param; + + nr_clear_queues(sk); + + sk->protinfo.nr->n2count = 0; + nr_write_internal(sk, NR_DISCREQ); + sk->protinfo.nr->state = NR_STATE_2; + + nr_start_t1timer(sk); + nr_stop_t2timer(sk); + nr_stop_t4timer(sk); + + sk->state = TCP_CLOSE; + sk->err = 0; + sk->shutdown |= SEND_SHUTDOWN; + + if (!sk->dead) + sk->state_change(sk); + + sk->dead = 1; +} + +static void nr_t1timer_expiry(unsigned long param) +{ + struct sock *sk = (struct sock *)param; switch (sk->protinfo.nr->state) { + case NR_STATE_1: if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) { - nr_clear_queues(sk); - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->err = ETIMEDOUT; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + nr_disconnect(sk, ETIMEDOUT); + return; } else { sk->protinfo.nr->n2count++; nr_write_internal(sk, NR_CONNREQ); @@ -137,14 +225,8 @@ static void nr_timer(unsigned long param) case NR_STATE_2: if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) { - nr_clear_queues(sk); - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->err = ETIMEDOUT; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + nr_disconnect(sk, ETIMEDOUT); + return; } else { sk->protinfo.nr->n2count++; nr_write_internal(sk, NR_DISCREQ); @@ -153,14 +235,8 @@ static void nr_timer(unsigned long param) case NR_STATE_3: if (sk->protinfo.nr->n2count == sk->protinfo.nr->n2) { - nr_clear_queues(sk); - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->err = ETIMEDOUT; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + nr_disconnect(sk, ETIMEDOUT); + return; } else { sk->protinfo.nr->n2count++; nr_requeue_frames(sk); @@ -168,9 +244,7 @@ static void nr_timer(unsigned long param) break; } - sk->protinfo.nr->t1timer = sk->protinfo.nr->t1; - - nr_set_timer(sk); + nr_start_t1timer(sk); } #endif diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c index c6a415ee6..3ce3e71f2 100644 --- a/net/netrom/sysctl_net_netrom.c +++ b/net/netrom/sysctl_net_netrom.c @@ -17,16 +17,16 @@ static int min_quality[] = {0}, max_quality[] = {255}; static int min_obs[] = {0}, max_obs[] = {255}; static int min_ttl[] = {0}, max_ttl[] = {255}; -static int min_t1[] = {5 * NR_SLOWHZ}; -static int max_t1[] = {600 * NR_SLOWHZ}; +static int min_t1[] = {5 * HZ}; +static int max_t1[] = {600 * HZ}; static int min_n2[] = {2}, max_n2[] = {127}; -static int min_t2[] = {1 * NR_SLOWHZ}; -static int max_t2[] = {60 * NR_SLOWHZ}; -static int min_t4[] = {1 * NR_SLOWHZ}; -static int max_t4[] = {1000 * NR_SLOWHZ}; +static int min_t2[] = {1 * HZ}; +static int max_t2[] = {60 * HZ}; +static int min_t4[] = {1 * HZ}; +static int max_t4[] = {1000 * HZ}; static int min_window[] = {1}, max_window[] = {127}; -static int min_idle[] = {0 * NR_SLOWHZ}; -static int max_idle[] = {65535 * NR_SLOWHZ}; +static int min_idle[] = {0 * HZ}; +static int max_idle[] = {65535 * HZ}; static int min_route[] = {0}, max_route[] = {1}; static int min_fails[] = {1}, max_fails[] = {10}; |