diff options
Diffstat (limited to 'net/rose')
-rw-r--r-- | net/rose/af_rose.c | 224 | ||||
-rw-r--r-- | net/rose/rose_dev.c | 4 | ||||
-rw-r--r-- | net/rose/rose_in.c | 95 | ||||
-rw-r--r-- | net/rose/rose_link.c | 111 | ||||
-rw-r--r-- | net/rose/rose_out.c | 58 | ||||
-rw-r--r-- | net/rose/rose_route.c | 162 | ||||
-rw-r--r-- | net/rose/rose_subr.c | 56 | ||||
-rw-r--r-- | net/rose/rose_timer.c | 172 | ||||
-rw-r--r-- | net/rose/sysctl_net_rose.c | 12 |
9 files changed, 560 insertions, 334 deletions
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 9896de9cb..134eee17a 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1,5 +1,5 @@ /* - * ROSE release 002 + * ROSE release 003 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -17,6 +17,9 @@ * ROSE 002 Jonathan(G4KLX) Changed hdrincl to qbitincl. * Added random number facilities entry. * Variable number of ROSE devices. + * ROSE 003 Jonathan(G4KLX) New timer architecture. + * Implemented idle timer. + * Added use count to neighbour. */ #include <linux/config.h> @@ -172,8 +175,7 @@ static void rose_remove_socket(struct sock *sk) struct sock *s; unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); cli(); if ((s = rose_list) == sk) { rose_list = s->next; @@ -204,13 +206,9 @@ void rose_kill_by_neigh(struct rose_neigh *neigh) for (s = rose_list; s != NULL; s = s->next) { if (s->protinfo.rose->neighbour == neigh) { - s->protinfo.rose->state = ROSE_STATE_0; + rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); + s->protinfo.rose->neighbour->use--; s->protinfo.rose->neighbour = NULL; - s->state = TCP_CLOSE; - s->err = ENETUNREACH; - s->shutdown |= SEND_SHUTDOWN; - s->state_change(s); - s->dead = 1; } } } @@ -224,13 +222,9 @@ static void rose_kill_by_device(struct device *dev) for (s = rose_list; s != NULL; s = s->next) { if (s->protinfo.rose->device == dev) { - s->protinfo.rose->state = ROSE_STATE_0; + rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); + s->protinfo.rose->neighbour->use--; s->protinfo.rose->device = NULL; - s->state = TCP_CLOSE; - s->err = ENETUNREACH; - s->shutdown |= SEND_SHUTDOWN; - s->state_change(s); - s->dead = 1; } } } @@ -265,8 +259,7 @@ static void rose_insert_socket(struct sock *sk) { unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); cli(); sk->next = rose_list; rose_list = sk; @@ -283,8 +276,7 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call) unsigned long flags; struct sock *s; - save_flags(flags); - cli(); + save_flags(flags); cli(); for (s = rose_list; s != NULL; s = s->next) { if (rosecmp(&s->protinfo.rose->source_addr, addr) == 0 && ax25cmp(&s->protinfo.rose->source_call, call) == 0 && s->protinfo.rose->source_ndigis == 0 && s->state == TCP_LISTEN) { @@ -312,8 +304,7 @@ struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh) struct sock *s; unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); cli(); for (s = rose_list; s != NULL; s = s->next) { if (s->protinfo.rose->lci == lci && s->protinfo.rose->neighbour == neigh) { @@ -371,10 +362,11 @@ void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the time struct sk_buff *skb; unsigned long flags; - save_flags(flags); - cli(); + save_flags(flags); cli(); - del_timer(&sk->timer); + rose_stop_heartbeat(sk); + rose_stop_idletimer(sk); + rose_stop_timer(sk); rose_remove_socket(sk); rose_clear_queues(sk); /* Flush the queues */ @@ -382,7 +374,7 @@ void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the time 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 */ - rose_set_timer(skb->sk); + rose_start_heartbeat(skb->sk); skb->sk->protinfo.rose->state = ROSE_STATE_0; } @@ -424,34 +416,38 @@ static int rose_setsockopt(struct socket *sock, int level, int optname, return -EFAULT; switch (optname) { + case ROSE_DEFER: + sk->protinfo.rose->defer = opt ? 1 : 0; + return 0; + case ROSE_T1: if (opt < 1) return -EINVAL; - sk->protinfo.rose->t1 = opt * ROSE_SLOWHZ; + sk->protinfo.rose->t1 = opt * HZ; return 0; case ROSE_T2: if (opt < 1) return -EINVAL; - sk->protinfo.rose->t2 = opt * ROSE_SLOWHZ; + sk->protinfo.rose->t2 = opt * HZ; return 0; case ROSE_T3: if (opt < 1) return -EINVAL; - sk->protinfo.rose->t3 = opt * ROSE_SLOWHZ; + sk->protinfo.rose->t3 = opt * HZ; return 0; case ROSE_HOLDBACK: if (opt < 1) return -EINVAL; - sk->protinfo.rose->hb = opt * ROSE_SLOWHZ; + sk->protinfo.rose->hb = opt * HZ; return 0; case ROSE_IDLE: - if (opt < 1) + if (opt < 0) return -EINVAL; - sk->protinfo.rose->idle = opt * 60 * ROSE_SLOWHZ; + sk->protinfo.rose->idle = opt * 60 * HZ; return 0; case ROSE_QBITINCL: @@ -477,24 +473,28 @@ static int rose_getsockopt(struct socket *sock, int level, int optname, return -EFAULT; switch (optname) { + case ROSE_DEFER: + val = sk->protinfo.rose->defer; + break; + case ROSE_T1: - val = sk->protinfo.rose->t1 / ROSE_SLOWHZ; + val = sk->protinfo.rose->t1 / HZ; break; case ROSE_T2: - val = sk->protinfo.rose->t2 / ROSE_SLOWHZ; + val = sk->protinfo.rose->t2 / HZ; break; case ROSE_T3: - val = sk->protinfo.rose->t3 / ROSE_SLOWHZ; + val = sk->protinfo.rose->t3 / HZ; break; case ROSE_HOLDBACK: - val = sk->protinfo.rose->hb / ROSE_SLOWHZ; + val = sk->protinfo.rose->hb / HZ; break; case ROSE_IDLE: - val = sk->protinfo.rose->idle / (ROSE_SLOWHZ * 60); + val = sk->protinfo.rose->idle / (60 * HZ); break; case ROSE_QBITINCL: @@ -550,7 +550,10 @@ static int rose_create(struct socket *sock, int protocol) sock->ops = &rose_proto_ops; sk->protocol = protocol; - sk->mtu = ROSE_MTU; /* 128 */ + sk->mtu = ROSE_MTU; /* 253 */ + + init_timer(&rose->timer); + init_timer(&rose->idletimer); skb_queue_head_init(&rose->frag_queue); @@ -592,6 +595,9 @@ static struct sock *rose_make_new(struct sock *osk) sk->sleep = osk->sleep; sk->zapped = osk->zapped; + init_timer(&rose->timer); + init_timer(&rose->idletimer); + skb_queue_head_init(&rose->frag_queue); rose->t1 = osk->protinfo.rose->t1; @@ -600,6 +606,7 @@ static struct sock *rose_make_new(struct sock *osk) rose->hb = osk->protinfo.rose->hb; rose->idle = osk->protinfo.rose->idle; + rose->defer = osk->protinfo.rose->defer; rose->device = osk->protinfo.rose->device; rose->qbitincl = osk->protinfo.rose->qbitincl; @@ -625,28 +632,24 @@ static int rose_release(struct socket *sock, struct socket *peer) switch (sk->protinfo.rose->state) { case ROSE_STATE_0: - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; + rose_disconnect(sk, 0, -1, -1); rose_destroy_socket(sk); break; case ROSE_STATE_2: - sk->protinfo.rose->state = ROSE_STATE_0; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; + sk->protinfo.rose->neighbour->use--; + rose_disconnect(sk, 0, -1, -1); rose_destroy_socket(sk); - break; + break; case ROSE_STATE_1: case ROSE_STATE_3: case ROSE_STATE_4: + case ROSE_STATE_5: rose_clear_queues(sk); + rose_stop_idletimer(sk); rose_write_internal(sk, ROSE_CLEAR_REQUEST); - sk->protinfo.rose->timer = sk->protinfo.rose->t3; + rose_start_t3timer(sk); sk->protinfo.rose->state = ROSE_STATE_2; sk->state = TCP_CLOSE; sk->shutdown |= SEND_SHUTDOWN; @@ -714,6 +717,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le { struct sock *sk = sock->sk; struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; + unsigned char cause, diagnostic; ax25_address *user; struct device *dev; @@ -739,7 +743,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le if (addr->srose_family != AF_ROSE) return -EINVAL; - if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr)) == NULL) + if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic)) == NULL) return -ENETUNREACH; if ((sk->protinfo.rose->lci = rose_new_lci(sk->protinfo.rose->neighbour)) == 0) @@ -775,10 +779,12 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le sk->state = TCP_SYN_SENT; sk->protinfo.rose->state = ROSE_STATE_1; - sk->protinfo.rose->timer = sk->protinfo.rose->t1; - rose_write_internal(sk, ROSE_CALL_REQUEST); - rose_set_timer(sk); + sk->protinfo.rose->neighbour->use++; + + rose_write_internal(sk, ROSE_CALL_REQUEST); + rose_start_heartbeat(sk); + rose_start_t1timer(sk); /* Now the loop */ if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) @@ -911,11 +917,8 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne /* * skb->data points to the rose frame start */ - - /* - * XXX This is an error. - */ if (!rose_parse_facilities(skb, &facilities)) { + rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76); return 0; } @@ -925,7 +928,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne * We can't accept the Call Request. */ if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = rose_make_new(sk)) == NULL) { - rose_transmit_clear_request(neigh, lci, 0x01); + rose_transmit_clear_request(neigh, lci, ROSE_NETWORK_CONGESTION, 120); return 0; } @@ -944,14 +947,21 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne make->protinfo.rose->neighbour = neigh; make->protinfo.rose->device = dev; - rose_write_internal(make, ROSE_CALL_ACCEPTED); + make->protinfo.rose->neighbour->use++; + + if (sk->protinfo.rose->defer) { + make->protinfo.rose->state = ROSE_STATE_5; + } else { + rose_write_internal(make, ROSE_CALL_ACCEPTED); + make->protinfo.rose->state = ROSE_STATE_3; + rose_start_idletimer(make); + } make->protinfo.rose->condition = 0x00; make->protinfo.rose->vs = 0; make->protinfo.rose->va = 0; make->protinfo.rose->vr = 0; make->protinfo.rose->vl = 0; - make->protinfo.rose->state = ROSE_STATE_3; sk->ack_backlog++; make->pair = sk; @@ -959,7 +969,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_ne skb_queue_head(&sk->receive_queue, skb); - rose_set_timer(make); + rose_start_heartbeat(make); if (!sk->dead) sk->data_ready(sk, skb->len); @@ -1146,37 +1156,35 @@ static int rose_shutdown(struct socket *sk, int how) static int rose_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(unsigned int))) != 0) - return err; + case TIOCOUTQ: { + long amount; amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; - put_user(amount, (unsigned int *)arg); + if (put_user(amount, (unsigned 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(unsigned int))) != 0) - return err; - put_user(amount, (unsigned int *)arg); + amount = skb->len; + if (put_user(amount, (unsigned 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; @@ -1195,20 +1203,51 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCADDRT: case SIOCDELRT: + case SIOCRSCLRRT: if (!suser()) return -EPERM; return rose_rt_ioctl(cmd, (void *)arg); + case SIOCRSGCAUSE: { + struct rose_cause_struct rose_cause; + rose_cause.cause = sk->protinfo.rose->cause; + rose_cause.diagnostic = sk->protinfo.rose->diagnostic; + if (copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct))) + return -EFAULT; + return 0; + } + + case SIOCRSSCAUSE: { + struct rose_cause_struct rose_cause; + if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct))) + return -EFAULT; + sk->protinfo.rose->cause = rose_cause.cause; + sk->protinfo.rose->diagnostic = rose_cause.diagnostic; + return 0; + } + case SIOCRSL2CALL: if (!suser()) return -EPERM; - if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_address))) != 0) - return err; if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) ax25_listen_release(&rose_callsign, NULL); - copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address)); + if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address))) + return -EFAULT; if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) ax25_listen_register(&rose_callsign, NULL); return 0; + case SIOCRSACCEPT: + if (sk->protinfo.rose->state == ROSE_STATE_5) { + rose_write_internal(sk, ROSE_CALL_ACCEPTED); + rose_start_idletimer(sk); + sk->protinfo.rose->condition = 0x00; + sk->protinfo.rose->vs = 0; + sk->protinfo.rose->va = 0; + sk->protinfo.rose->vr = 0; + sk->protinfo.rose->vl = 0; + sk->protinfo.rose->state = ROSE_STATE_3; + } + return 0; + default: return dev_ioctl(cmd, (void *)arg); } @@ -1228,7 +1267,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i cli(); - len += sprintf(buffer, "dest_addr dest_call src_addr src_call dev lci st vs vr va t t1 t2 t3 hb Snd-Q Rcv-Q\n"); + len += sprintf(buffer, "dest_addr dest_call src_addr src_call dev lci st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q\n"); for (s = rose_list; s != NULL; s = s->next) { if ((dev = s->protinfo.rose->device) == NULL) @@ -1245,17 +1284,24 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length, i else callsign = ax2asc(&s->protinfo.rose->source_call); - len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %d %d %d %d %3d %3d %3d %3d %3d %5d %5d\n", - rose2asc(&s->protinfo.rose->source_addr), callsign, - devname, s->protinfo.rose->lci & 0x0FFF, + len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d\n", + rose2asc(&s->protinfo.rose->source_addr), + callsign, + devname, + s->protinfo.rose->lci & 0x0FFF, s->protinfo.rose->state, - s->protinfo.rose->vs, s->protinfo.rose->vr, s->protinfo.rose->va, - s->protinfo.rose->timer / ROSE_SLOWHZ, - s->protinfo.rose->t1 / ROSE_SLOWHZ, - s->protinfo.rose->t2 / ROSE_SLOWHZ, - s->protinfo.rose->t3 / ROSE_SLOWHZ, - s->protinfo.rose->hb / ROSE_SLOWHZ, - atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc)); + s->protinfo.rose->vs, + s->protinfo.rose->vr, + s->protinfo.rose->va, + ax25_display_timer(&s->protinfo.rose->timer) / HZ, + s->protinfo.rose->t1 / HZ, + s->protinfo.rose->t2 / HZ, + s->protinfo.rose->t3 / HZ, + s->protinfo.rose->hb / HZ, + ax25_display_timer(&s->protinfo.rose->idletimer) / (60 * HZ), + s->protinfo.rose->idle / (60 * HZ), + atomic_read(&s->wmem_alloc), + atomic_read(&s->rmem_alloc)); pos = begin + len; @@ -1360,7 +1406,7 @@ __initfunc(void rose_proto_init(struct net_proto *pro)) sock_register(&rose_family_ops); register_netdevice_notifier(&rose_dev_notifier); - printk(KERN_INFO "G4KLX ROSE for Linux. Version 0.2 for AX25.035 Linux 2.1\n"); + printk(KERN_INFO "G4KLX ROSE for Linux. Version 0.3 for AX25.037 Linux 2.1\n"); ax25_protocol_register(AX25_P_ROSE, rose_route_frame); ax25_linkfail_register(rose_link_failed); diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index 73d0aa552..7861220ee 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -1,5 +1,5 @@ /* - * ROSE release 002 + * ROSE release 003 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -101,7 +101,7 @@ static int rose_rebuild_header(struct sk_buff *skb) unsigned char *bp = (unsigned char *)skb->data; struct sk_buff *skbn; - if (!arp_find(bp + 7, skb)) { + if (arp_find(bp + 7, skb)) { kfree_skb(skb, FREE_WRITE); return 1; } diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c index 3c3e17b2b..1ac11528d 100644 --- a/net/rose/rose_in.c +++ b/net/rose/rose_in.c @@ -1,5 +1,5 @@ /* - * ROSE release 002 + * ROSE release 003 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -17,6 +17,8 @@ * * History * ROSE 001 Jonathan(G4KLX) Cloned from nr_in.c + * ROSE 002 Jonathan(G4KLX) Return cause and diagnostic codes from Clear Requests. + * ROSE 003 Jonathan(G4KLX) New timer architecture. */ #include <linux/config.h> @@ -48,6 +50,8 @@ static int rose_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) { struct sk_buff *skbo, *skbn = skb; + rose_start_idletimer(sk); + if (more) { sk->protinfo.rose->fraglen += skb->len; skb_queue_tail(&sk->protinfo.rose->frag_queue, skb); @@ -89,8 +93,9 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety switch (frametype) { case ROSE_CALL_ACCEPTED: + rose_stop_timer(sk); + rose_start_idletimer(sk); sk->protinfo.rose->condition = 0x00; - sk->protinfo.rose->timer = 0; sk->protinfo.rose->vs = 0; sk->protinfo.rose->va = 0; sk->protinfo.rose->vr = 0; @@ -102,15 +107,9 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety break; case ROSE_CLEAR_REQUEST: - rose_clear_queues(sk); rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - sk->protinfo.rose->state = ROSE_STATE_0; - sk->state = TCP_CLOSE; - sk->err = ECONNREFUSED; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); + sk->protinfo.rose->neighbour->use--; break; default: @@ -131,15 +130,13 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety case ROSE_CLEAR_REQUEST: rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); + sk->protinfo.rose->neighbour->use--; + break; + case ROSE_CLEAR_CONFIRMATION: - rose_clear_queues(sk); - sk->protinfo.rose->state = ROSE_STATE_0; - sk->state = TCP_CLOSE; - sk->err = 0; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + rose_disconnect(sk, 0, -1, -1); + sk->protinfo.rose->neighbour->use--; break; default: @@ -161,9 +158,10 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety switch (frametype) { case ROSE_RESET_REQUEST: + rose_stop_timer(sk); + rose_start_idletimer(sk); rose_write_internal(sk, ROSE_RESET_CONFIRMATION); sk->protinfo.rose->condition = 0x00; - sk->protinfo.rose->timer = 0; sk->protinfo.rose->vs = 0; sk->protinfo.rose->vr = 0; sk->protinfo.rose->va = 0; @@ -171,15 +169,9 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety break; case ROSE_CLEAR_REQUEST: - rose_clear_queues(sk); rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - sk->protinfo.rose->state = ROSE_STATE_0; - sk->state = TCP_CLOSE; - sk->err = 0; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); + sk->protinfo.rose->neighbour->use--; break; case ROSE_RR: @@ -189,7 +181,6 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety else sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY; if (!rose_validate_nr(sk, nr)) { - rose_clear_queues(sk); rose_write_internal(sk, ROSE_RESET_REQUEST); sk->protinfo.rose->condition = 0x00; sk->protinfo.rose->vs = 0; @@ -197,7 +188,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety sk->protinfo.rose->va = 0; sk->protinfo.rose->vl = 0; sk->protinfo.rose->state = ROSE_STATE_4; - sk->protinfo.rose->timer = sk->protinfo.rose->t2; + rose_start_t2timer(sk); + rose_stop_idletimer(sk); } else { if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) { sk->protinfo.rose->va = nr; @@ -210,7 +202,6 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety case ROSE_DATA: /* XXX */ sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY; if (!rose_validate_nr(sk, nr)) { - rose_clear_queues(sk); rose_write_internal(sk, ROSE_RESET_REQUEST); sk->protinfo.rose->condition = 0x00; sk->protinfo.rose->vs = 0; @@ -218,7 +209,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety sk->protinfo.rose->va = 0; sk->protinfo.rose->vl = 0; sk->protinfo.rose->state = ROSE_STATE_4; - sk->protinfo.rose->timer = sk->protinfo.rose->t2; + rose_start_t2timer(sk); + rose_stop_idletimer(sk); break; } if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) { @@ -242,11 +234,11 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety */ if (((sk->protinfo.rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == sk->protinfo.rose->vr) { sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; - sk->protinfo.rose->timer = 0; + rose_stop_timer(sk); rose_enquiry_response(sk); } else { sk->protinfo.rose->condition |= ROSE_COND_ACK_PENDING; - sk->protinfo.rose->timer = sk->protinfo.rose->hb; + rose_start_hbtimer(sk); } break; @@ -270,7 +262,8 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety case ROSE_RESET_REQUEST: rose_write_internal(sk, ROSE_RESET_CONFIRMATION); case ROSE_RESET_CONFIRMATION: - sk->protinfo.rose->timer = 0; + rose_stop_timer(sk); + rose_start_idletimer(sk); sk->protinfo.rose->condition = 0x00; sk->protinfo.rose->va = 0; sk->protinfo.rose->vr = 0; @@ -280,16 +273,9 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety break; case ROSE_CLEAR_REQUEST: - rose_clear_queues(sk); rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); - sk->protinfo.rose->timer = 0; - sk->protinfo.rose->state = ROSE_STATE_0; - sk->state = TCP_CLOSE; - sk->err = 0; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); + sk->protinfo.rose->neighbour->use--; break; default: @@ -299,6 +285,22 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety return 0; } +/* + * State machine for state 5, Awaiting Call Acceptance State. + * The handling of the timer(s) is in file rose_timer.c + * Handling of state 0 and connection release is in af_rose.c. + */ +static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype) +{ + if (frametype == ROSE_CLEAR_REQUEST) { + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); + sk->protinfo.rose->neighbour->use--; + } + + return 0; +} + /* Higher level upcall for a LAPB frame */ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) { @@ -307,8 +309,6 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) if (sk->protinfo.rose->state == ROSE_STATE_0) return 0; - del_timer(&sk->timer); - frametype = rose_decode(skb, &ns, &nr, &q, &d, &m); switch (sk->protinfo.rose->state) { @@ -324,9 +324,12 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb) case ROSE_STATE_4: queued = rose_state4_machine(sk, skb, frametype); break; + case ROSE_STATE_5: + queued = rose_state5_machine(sk, skb, frametype); + break; } - rose_set_timer(sk); + rose_kick(sk); return queued; } diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c index 86626511e..b481e485f 100644 --- a/net/rose/rose_link.c +++ b/net/rose/rose_link.c @@ -1,5 +1,5 @@ /* - * ROSE release 002 + * ROSE release 003 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -11,6 +11,7 @@ * * History * ROSE 001 Jonathan(G4KLX) Cloned from rose_timer.c + * ROSE 003 Jonathan(G4KLX) New timer architecture. */ #include <linux/config.h> @@ -38,53 +39,64 @@ #include <linux/firewall.h> #include <net/rose.h> -static void rose_link_timer(unsigned long); +static void rose_ftimer_expiry(unsigned long); +static void rose_t0timer_expiry(unsigned long); -/* - * Linux set timer - */ -void rose_link_set_timer(struct rose_neigh *neigh) +void rose_start_ftimer(struct rose_neigh *neigh) { - unsigned long flags; + del_timer(&neigh->ftimer); - save_flags(flags); cli(); - del_timer(&neigh->timer); - restore_flags(flags); + neigh->ftimer.data = (unsigned long)neigh; + neigh->ftimer.function = &rose_ftimer_expiry; + neigh->ftimer.expires = jiffies + sysctl_rose_link_fail_timeout; - neigh->timer.data = (unsigned long)neigh; - neigh->timer.function = &rose_link_timer; - neigh->timer.expires = jiffies + (HZ / 10); + add_timer(&neigh->ftimer); +} + +void rose_start_t0timer(struct rose_neigh *neigh) +{ + del_timer(&neigh->t0timer); - add_timer(&neigh->timer); + neigh->t0timer.data = (unsigned long)neigh; + neigh->t0timer.function = &rose_t0timer_expiry; + neigh->t0timer.expires = jiffies + sysctl_rose_restart_request_timeout; + + add_timer(&neigh->t0timer); } -/* - * ROSE Link Timer - * - * This routine is called every 100ms. Decrement timer by this - * amount - if expired then process the event. - */ -static void rose_link_timer(unsigned long param) +void rose_stop_ftimer(struct rose_neigh *neigh) { - struct rose_neigh *neigh = (struct rose_neigh *)param; + del_timer(&neigh->ftimer); +} - if (neigh->ftimer > 0) - neigh->ftimer--; +void rose_stop_t0timer(struct rose_neigh *neigh) +{ + del_timer(&neigh->t0timer); +} - if (neigh->t0timer > 0) { - neigh->t0timer--; +int rose_ftimer_running(struct rose_neigh *neigh) +{ + return (neigh->ftimer.prev != NULL || neigh->ftimer.next != NULL); +} - if (neigh->t0timer == 0) { - rose_transmit_restart_request(neigh); - neigh->dce_mode = 0; - neigh->t0timer = sysctl_rose_restart_request_timeout; - } - } +int rose_t0timer_running(struct rose_neigh *neigh) +{ + return (neigh->t0timer.prev != NULL || neigh->t0timer.next != NULL); +} - if (neigh->ftimer > 0 || neigh->t0timer > 0) - rose_link_set_timer(neigh); - else - del_timer(&neigh->timer); +static void rose_ftimer_expiry(unsigned long param) +{ +} + +static void rose_t0timer_expiry(unsigned long param) +{ + struct rose_neigh *neigh = (struct rose_neigh *)param; + + rose_transmit_restart_request(neigh); + + neigh->dce_mode = 0; + + rose_start_t0timer(neigh); } /* @@ -101,7 +113,9 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh) else rose_call = &rose_callsign; - return ax25_send_frame(skb, 256, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); + neigh->ax25 = ax25_send_frame(skb, 256, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); + + return (neigh->ax25 != NULL); } /* @@ -118,7 +132,9 @@ static int rose_link_up(struct rose_neigh *neigh) else rose_call = &rose_callsign; - return ax25_link_up(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); + neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); + + return (neigh->ax25 != NULL); } /* @@ -130,17 +146,15 @@ void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigne switch (frametype) { case ROSE_RESTART_REQUEST: - neigh->t0timer = 0; + rose_stop_t0timer(neigh); neigh->restarted = 1; - neigh->dce_mode = (skb->data[3] == 0x00); - del_timer(&neigh->timer); + neigh->dce_mode = (skb->data[3] == ROSE_DTE_ORIGINATED); rose_transmit_restart_confirmation(neigh); break; case ROSE_RESTART_CONFIRMATION: - neigh->t0timer = 0; + rose_stop_t0timer(neigh); neigh->restarted = 1; - del_timer(&neigh->timer); break; case ROSE_DIAGNOSTIC: @@ -181,7 +195,7 @@ void rose_transmit_restart_request(struct rose_neigh *neigh) *dptr++ = ROSE_GFI; *dptr++ = 0x00; *dptr++ = ROSE_RESTART_REQUEST; - *dptr++ = 0x00; + *dptr++ = ROSE_DTE_ORIGINATED; *dptr++ = 0; if (!rose_send_frame(skb, neigh)) @@ -247,7 +261,7 @@ void rose_transmit_diagnostic(struct rose_neigh *neigh, unsigned char diag) * This routine is called when a Clear Request is needed outside of the context * of a connected socket. */ -void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause) +void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause, unsigned char diagnostic) { struct sk_buff *skb; unsigned char *dptr; @@ -267,7 +281,7 @@ void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, uns *dptr++ = ((lci >> 0) & 0xFF); *dptr++ = ROSE_CLEAR_REQUEST; *dptr++ = cause; - *dptr++ = 0x00; + *dptr++ = diagnostic; if (!rose_send_frame(skb, neigh)) kfree_skb(skb, FREE_WRITE); @@ -294,11 +308,10 @@ void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh) } else { skb_queue_tail(&neigh->queue, skb); - if (neigh->t0timer == 0) { + if (!rose_t0timer_running(neigh)) { rose_transmit_restart_request(neigh); neigh->dce_mode = 0; - neigh->t0timer = sysctl_rose_restart_request_timeout; - rose_link_set_timer(neigh); + rose_start_t0timer(neigh); } } } diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c index f0e212dc3..0ed9f7480 100644 --- a/net/rose/rose_out.c +++ b/net/rose/rose_out.c @@ -1,5 +1,5 @@ /* - * ROSE release 002 + * ROSE release 003 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -11,6 +11,7 @@ * * History * ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c + * ROSE 003 Jonathan(G4KLX) New timer architecture. */ #include <linux/config.h> @@ -80,8 +81,7 @@ void rose_output(struct sock *sk, struct sk_buff *skb) skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */ } - if (sk->protinfo.rose->state == ROSE_STATE_3) - rose_kick(sk); + rose_kick(sk); } /* @@ -96,6 +96,8 @@ static void rose_send_iframe(struct sock *sk, struct sk_buff *skb) skb->data[2] |= (sk->protinfo.rose->vr << 5) & 0xE0; skb->data[2] |= (sk->protinfo.rose->vs << 1) & 0x0E; + rose_start_idletimer(sk); + rose_transmit_link(skb, sk->protinfo.rose->neighbour); } @@ -104,36 +106,41 @@ void rose_kick(struct sock *sk) struct sk_buff *skb; unsigned short end; - del_timer(&sk->timer); + if (sk->protinfo.rose->state != ROSE_STATE_3) + return; + + if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) + return; + + if (skb_peek(&sk->write_queue) == NULL) + return; end = (sk->protinfo.rose->va + sysctl_rose_window_size) % ROSE_MODULUS; - if (!(sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) && - sk->protinfo.rose->vs != end && - skb_peek(&sk->write_queue) != NULL) { - /* - * Transmit data until either we're out of data to send or - * the window is full. - */ + if (sk->protinfo.rose->vs == end) + return; - skb = skb_dequeue(&sk->write_queue); + /* + * Transmit data until either we're out of data to send or + * the window is full. + */ - do { - /* - * Transmit the frame. - */ - rose_send_iframe(sk, skb); + skb = skb_dequeue(&sk->write_queue); - sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS; + do { + /* + * Transmit the frame. + */ + rose_send_iframe(sk, skb); - } while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL); + sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS; - sk->protinfo.rose->vl = sk->protinfo.rose->vr; - sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; - sk->protinfo.rose->timer = 0; - } + } while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL); - rose_set_timer(sk); + sk->protinfo.rose->vl = sk->protinfo.rose->vr; + sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; + + rose_stop_timer(sk); } /* @@ -150,7 +157,8 @@ void rose_enquiry_response(struct sock *sk) sk->protinfo.rose->vl = sk->protinfo.rose->vr; sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; - sk->protinfo.rose->timer = 0; + + rose_stop_timer(sk); } void rose_check_iframes_acked(struct sock *sk, unsigned short nr) diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 5b1338609..43358644c 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -1,5 +1,5 @@ /* - * ROSE release 002 + * ROSE release 003 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -15,6 +15,8 @@ * address masks. * ROSE 002 Jonathan(G4KLX) Uprated through routing of packets. * Routing loop detection. + * ROSE 003 Jonathan(G4KLX) New timer architecture. + * Added use count to neighbours. */ #include <linux/config.h> @@ -80,24 +82,32 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct device *de rose_neigh->callsign = rose_route->neighbour; rose_neigh->digipeat = NULL; + rose_neigh->ax25 = NULL; rose_neigh->dev = dev; rose_neigh->count = 0; + rose_neigh->use = 0; rose_neigh->dce_mode = 0; rose_neigh->number = rose_neigh_no++; rose_neigh->restarted = 0; + skb_queue_head_init(&rose_neigh->queue); - rose_neigh->t0timer = 0; - rose_neigh->ftimer = 0; - init_timer(&rose_neigh->timer); + + init_timer(&rose_neigh->ftimer); + init_timer(&rose_neigh->t0timer); if (rose_route->ndigis != 0) { if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) { kfree(rose_neigh); return -ENOMEM; } - rose_neigh->digipeat->ndigi = rose_route->ndigis; - for (i = 0; i < rose_route->ndigis; i++) - rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i]; + + rose_neigh->digipeat->ndigi = rose_route->ndigis; + rose_neigh->digipeat->lastrepeat = -1; + + for (i = 0; i < rose_route->ndigis; i++) { + rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i]; + rose_neigh->digipeat->repeated[i] = 0; + } } save_flags(flags); cli(); @@ -207,13 +217,13 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) unsigned long flags; struct sk_buff *skb; - del_timer(&rose_neigh->timer); + rose_stop_ftimer(rose_neigh); + rose_stop_t0timer(rose_neigh); while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL) kfree_skb(skb, FREE_WRITE); - save_flags(flags); - cli(); + save_flags(flags); cli(); if ((s = rose_neigh_list) == rose_neigh) { rose_neigh_list = rose_neigh->next; @@ -244,9 +254,14 @@ static void rose_remove_route(struct rose_route *rose_route) { struct rose_route *s; unsigned long flags; - - save_flags(flags); - cli(); + + if (rose_route->neigh1 != NULL) + rose_route->neigh1->use--; + + if (rose_route->neigh2 != NULL) + rose_route->neigh2->use--; + + save_flags(flags); cli(); if ((s = rose_route_list) == rose_route) { rose_route_list = rose_route->next; @@ -295,7 +310,7 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct device *de if (rose_node->neighbour[i] == rose_neigh) { rose_neigh->count--; - if (rose_neigh->count == 0) + if (rose_neigh->count == 0 && rose_neigh->use == 0) rose_remove_neigh(rose_neigh); rose_node->count--; @@ -381,6 +396,35 @@ void rose_route_device_down(struct device *dev) } /* + * Clear all nodes and neighbours out, except for neighbours with + * active connections going through them. + */ +static int rose_clear_routes(void) +{ + struct rose_neigh *s, *rose_neigh = rose_neigh_list; + struct rose_node *t, *rose_node = rose_node_list; + + while (rose_node != NULL) { + t = rose_node; + rose_node = rose_node->next; + + rose_remove_node(t); + } + + while (rose_neigh != NULL) { + s = rose_neigh; + rose_neigh = rose_neigh->next; + + s->count = 0; + + if (s->use == 0) + rose_remove_neigh(s); + } + + return 0; +} + +/* * Check that the device given is a valid AX.25 interface that is "up". */ struct device *rose_ax25_dev_get(char *devname) @@ -440,20 +484,31 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig /* * Find a neighbour given a ROSE address. */ -struct rose_neigh *rose_get_neigh(rose_address *addr) +struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsigned char *diagnostic) { struct rose_node *node; + int failed = 0; int i; for (node = rose_node_list; node != NULL; node = node->next) { if (rosecmpm(addr, &node->address, node->mask) == 0) { for (i = 0; i < node->count; i++) { - if (node->neighbour[i]->ftimer == 0) + if (!rose_ftimer_running(node->neighbour[i])) return node->neighbour[i]; + else + failed = 1; } } } + if (failed) { + *cause = ROSE_OUT_OF_ORDER; + *diagnostic = 0; + } else { + *cause = ROSE_NOT_OBTAINABLE; + *diagnostic = 0; + } + return NULL; } @@ -464,14 +519,12 @@ int rose_rt_ioctl(unsigned int cmd, void *arg) { struct rose_route_struct rose_route; struct device *dev; - int err; switch (cmd) { case SIOCADDRT: - if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0) - return err; - copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)); + if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) + return -EFAULT; if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) return -EINVAL; if (rose_dev_get(&rose_route.address) != NULL) /* Can't add routes to ourself */ @@ -482,13 +535,15 @@ int rose_rt_ioctl(unsigned int cmd, void *arg) return rose_add_node(&rose_route, dev); case SIOCDELRT: - if ((err = verify_area(VERIFY_READ, arg, sizeof(struct rose_route_struct))) != 0) - return err; - copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)); + if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) + return -EFAULT; if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) return -EINVAL; return rose_del_node(&rose_route, dev); + case SIOCRSCLRRT: + return rose_clear_routes(); + default: return -EINVAL; } @@ -502,10 +557,9 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh) struct sk_buff *skb; rose_neigh->restarted = 0; - rose_neigh->t0timer = 0; - rose_neigh->ftimer = sysctl_rose_link_fail_timeout; - rose_link_set_timer(rose_neigh); + rose_stop_t0timer(rose_neigh); + rose_start_ftimer(rose_neigh); while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL) kfree_skb(skb, FREE_WRITE); @@ -523,13 +577,15 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh) } if (rose_route->neigh1 == rose_neigh) { + rose_route->neigh1->use--; rose_route->neigh1 = NULL; - rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, 0x0D); + rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0); } if (rose_route->neigh2 == rose_neigh) { + rose_route->neigh2->use--; rose_route->neigh2 = NULL; - rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, 0x0D); + rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0); } rose_route = rose_route->next; @@ -541,16 +597,18 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh) * then don't use that neighbour until it is reset. Blow away all through * routes and connections using this route. */ -void rose_link_failed(ax25_address *callsign, struct device *dev) +void rose_link_failed(ax25_cb *ax25, int reason) { struct rose_neigh *rose_neigh; for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) - if (ax25cmp(&rose_neigh->callsign, callsign) == 0 && rose_neigh->dev == dev) + if (rose_neigh->ax25 == ax25) break; if (rose_neigh == NULL) return; + rose_neigh->ax25 = NULL; + rose_del_route_by_neigh(rose_neigh); rose_kill_by_neigh(rose_neigh); } @@ -583,6 +641,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) struct sock *sk; unsigned short frametype; unsigned int lci, new_lci; + unsigned char cause, diagnostic; struct device *dev; unsigned long flags; @@ -604,7 +663,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) /* * Obviously the link is working, halt the ftimer. */ - rose_neigh->ftimer = 0; + rose_stop_ftimer(rose_neigh); /* * LCI of zero is always for us, and its always a restart @@ -631,7 +690,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) return rose_rx_call_request(skb, dev, rose_neigh, lci); if (!sysctl_rose_routing_control) { - rose_transmit_clear_request(rose_neigh, lci, 0x0D); + rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0); return 0; } @@ -679,7 +738,10 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) if (frametype != ROSE_CALL_REQUEST) /* XXX */ return 0; - rose_parse_facilities(skb, &facilities); + if (!rose_parse_facilities(skb, &facilities)) { + rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76); + return 0; + } /* * Check for routing loops. @@ -691,25 +753,25 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) { printk(KERN_DEBUG "ROSE: routing loop from %s\n", rose2asc(src_addr)); printk(KERN_DEBUG "ROSE: to %s\n", rose2asc(dest_addr)); - rose_transmit_clear_request(rose_neigh, lci, 0x0D); + rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120); return 0; } } - if ((new_neigh = rose_get_neigh(dest_addr)) == NULL) { - printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr)); - rose_transmit_clear_request(rose_neigh, lci, 0x0D); + if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) { + if (cause == ROSE_NOT_OBTAINABLE) + printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr)); + rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic); return 0; } if ((new_lci = rose_new_lci(new_neigh)) == 0) { - printk(KERN_DEBUG "ROSE: no spare VCs to %s\n", rose2asc(dest_addr)); - rose_transmit_clear_request(rose_neigh, lci, 0x0D); + rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71); return 0; } if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) { - rose_transmit_clear_request(rose_neigh, lci, 0x0D); + rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120); return 0; } @@ -723,6 +785,9 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) rose_route->lci2 = new_lci; rose_route->neigh2 = new_neigh; + rose_route->neigh1->use++; + rose_route->neigh2->use++; + save_flags(flags); cli(); rose_route->next = rose_route_list; rose_route_list = rose_route; @@ -790,21 +855,30 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int len = 0; off_t pos = 0; off_t begin = 0; + int i; cli(); - len += sprintf(buffer, "addr callsign dev count mode restart t0 tf\n"); + len += sprintf(buffer, "addr callsign dev count use mode restart t0 tf digipeaters\n"); for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) { - len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3s %3s %3d %3d\n", + len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu", rose_neigh->number, ax2asc(&rose_neigh->callsign), rose_neigh->dev ? rose_neigh->dev->name : "???", rose_neigh->count, + rose_neigh->use, (rose_neigh->dce_mode) ? "DCE" : "DTE", (rose_neigh->restarted) ? "yes" : "no", - rose_neigh->t0timer / ROSE_SLOWHZ, - rose_neigh->ftimer / ROSE_SLOWHZ); + ax25_display_timer(&rose_neigh->t0timer) / HZ, + ax25_display_timer(&rose_neigh->ftimer) / HZ); + + if (rose_neigh->digipeat != NULL) { + for (i = 0; i < rose_neigh->digipeat->ndigi; i++) + len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i])); + } + + len += sprintf(buffer + len, "\n"); pos = begin + len; diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c index 4e0530cb4..ee710bd6e 100644 --- a/net/rose/rose_subr.c +++ b/net/rose/rose_subr.c @@ -1,5 +1,5 @@ /* - * ROSE release 002 + * ROSE release 003 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -11,6 +11,8 @@ * * History * ROSE 001 Jonathan(G4KLX) Cloned from nr_subr.c + * ROSE 002 Jonathan(G4KLX) Centralised disconnect processing. + * ROSE 003 Jonathan(G4KLX) Added use count to neighbours. */ #include <linux/config.h> @@ -92,12 +94,8 @@ void rose_write_internal(struct sock *sk, int frametype) case ROSE_CALL_ACCEPTED: case ROSE_CLEAR_REQUEST: case ROSE_RESET_REQUEST: - case ROSE_DIAGNOSTIC: len += 2; break; - case ROSE_INTERRUPT: - len += 1; - break; } if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) @@ -137,24 +135,23 @@ void rose_write_internal(struct sock *sk, int frametype) break; case ROSE_CLEAR_REQUEST: - case ROSE_RESET_REQUEST: *dptr++ = ROSE_GFI | lci1; *dptr++ = lci2; *dptr++ = frametype; - *dptr++ = 0x00; /* XXX */ - *dptr++ = 0x00; /* XXX */ + *dptr++ = sk->protinfo.rose->cause; + *dptr++ = sk->protinfo.rose->diagnostic; break; - case ROSE_INTERRUPT: + case ROSE_RESET_REQUEST: *dptr++ = ROSE_GFI | lci1; *dptr++ = lci2; *dptr++ = frametype; - *dptr++ = 0x00; /* XXX */ + *dptr++ = ROSE_DTE_ORIGINATED; + *dptr++ = 0; break; case ROSE_RR: case ROSE_RNR: - case ROSE_REJ: *dptr++ = ROSE_GFI | lci1; *dptr++ = lci2; *dptr = frametype; @@ -162,7 +159,6 @@ void rose_write_internal(struct sock *sk, int frametype) break; case ROSE_CLEAR_CONFIRMATION: - case ROSE_INTERRUPT_CONFIRMATION: case ROSE_RESET_CONFIRMATION: *dptr++ = ROSE_GFI | lci1; *dptr++ = lci2; @@ -191,23 +187,15 @@ int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m) case ROSE_CALL_ACCEPTED: case ROSE_CLEAR_REQUEST: case ROSE_CLEAR_CONFIRMATION: - case ROSE_INTERRUPT: - case ROSE_INTERRUPT_CONFIRMATION: case ROSE_RESET_REQUEST: case ROSE_RESET_CONFIRMATION: - case ROSE_RESTART_REQUEST: - case ROSE_RESTART_CONFIRMATION: - case ROSE_REGISTRATION_REQUEST: - case ROSE_REGISTRATION_CONFIRMATION: - case ROSE_DIAGNOSTIC: return frame[2]; default: break; } if ((frame[2] & 0x1F) == ROSE_RR || - (frame[2] & 0x1F) == ROSE_RNR || - (frame[2] & 0x1F) == ROSE_REJ) { + (frame[2] & 0x1F) == ROSE_RNR) { *nr = (frame[2] >> 5) & 0x07; return frame[2] & 0x1F; } @@ -437,4 +425,30 @@ int rose_create_facilities(unsigned char *buffer, rose_cb *rose) return len; } +void rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic) +{ + rose_stop_timer(sk); + rose_stop_idletimer(sk); + + rose_clear_queues(sk); + + sk->protinfo.rose->lci = 0; + sk->protinfo.rose->state = ROSE_STATE_0; + + if (cause != -1) + sk->protinfo.rose->cause = cause; + + if (diagnostic != -1) + sk->protinfo.rose->diagnostic = diagnostic; + + 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/rose/rose_timer.c b/net/rose/rose_timer.c index 572975e5d..718a64ec0 100644 --- a/net/rose/rose_timer.c +++ b/net/rose/rose_timer.c @@ -1,5 +1,5 @@ /* - * ROSE release 002 + * ROSE release 003 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -11,6 +11,8 @@ * * History * ROSE 001 Jonathan(G4KLX) Cloned from nr_timer.c + * ROSE 003 Jonathan(G4KLX) New timer architecture. + * Implemented idle timer. */ #include <linux/config.h> @@ -37,42 +39,103 @@ #include <linux/interrupt.h> #include <net/rose.h> -static void rose_timer(unsigned long); +static void rose_heartbeat_expiry(unsigned long); +static void rose_timer_expiry(unsigned long); +static void rose_idletimer_expiry(unsigned long); -/* - * Linux set timer - */ -void rose_set_timer(struct sock *sk) +void rose_start_heartbeat(struct sock *sk) { - unsigned long flags; - - save_flags(flags); cli(); del_timer(&sk->timer); - restore_flags(flags); sk->timer.data = (unsigned long)sk; - sk->timer.function = &rose_timer; - sk->timer.expires = jiffies + (HZ / 10); + sk->timer.function = &rose_heartbeat_expiry; + sk->timer.expires = jiffies + 5 * HZ; add_timer(&sk->timer); } -/* - * ROSE Timer - * - * This routine is called every 100ms. Decrement timer by this - * amount - if expired then process the event. - */ -static void rose_timer(unsigned long param) +void rose_start_t1timer(struct sock *sk) +{ + del_timer(&sk->protinfo.rose->timer); + + sk->protinfo.rose->timer.data = (unsigned long)sk; + sk->protinfo.rose->timer.function = &rose_timer_expiry; + sk->protinfo.rose->timer.expires = jiffies + sk->protinfo.rose->t1; + + add_timer(&sk->protinfo.rose->timer); +} + +void rose_start_t2timer(struct sock *sk) +{ + del_timer(&sk->protinfo.rose->timer); + + sk->protinfo.rose->timer.data = (unsigned long)sk; + sk->protinfo.rose->timer.function = &rose_timer_expiry; + sk->protinfo.rose->timer.expires = jiffies + sk->protinfo.rose->t2; + + add_timer(&sk->protinfo.rose->timer); +} + +void rose_start_t3timer(struct sock *sk) +{ + del_timer(&sk->protinfo.rose->timer); + + sk->protinfo.rose->timer.data = (unsigned long)sk; + sk->protinfo.rose->timer.function = &rose_timer_expiry; + sk->protinfo.rose->timer.expires = jiffies + sk->protinfo.rose->t3; + + add_timer(&sk->protinfo.rose->timer); +} + +void rose_start_hbtimer(struct sock *sk) +{ + del_timer(&sk->protinfo.rose->timer); + + sk->protinfo.rose->timer.data = (unsigned long)sk; + sk->protinfo.rose->timer.function = &rose_timer_expiry; + sk->protinfo.rose->timer.expires = jiffies + sk->protinfo.rose->hb; + + add_timer(&sk->protinfo.rose->timer); +} + +void rose_start_idletimer(struct sock *sk) +{ + del_timer(&sk->protinfo.rose->idletimer); + + if (sk->protinfo.rose->idle > 0) { + sk->protinfo.rose->idletimer.data = (unsigned long)sk; + sk->protinfo.rose->idletimer.function = &rose_idletimer_expiry; + sk->protinfo.rose->idletimer.expires = jiffies + sk->protinfo.rose->idle; + + add_timer(&sk->protinfo.rose->idletimer); + } +} + +void rose_stop_heartbeat(struct sock *sk) +{ + del_timer(&sk->timer); +} + +void rose_stop_timer(struct sock *sk) +{ + del_timer(&sk->protinfo.rose->timer); +} + +void rose_stop_idletimer(struct sock *sk) +{ + del_timer(&sk->protinfo.rose->idletimer); +} + +static void rose_heartbeat_expiry(unsigned long param) { struct sock *sk = (struct sock *)param; switch (sk->protinfo.rose->state) { + case ROSE_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); rose_destroy_socket(sk); return; } @@ -87,57 +150,62 @@ static void rose_timer(unsigned long param) sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY; sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; sk->protinfo.rose->vl = sk->protinfo.rose->vr; - sk->protinfo.rose->timer = 0; rose_write_internal(sk, ROSE_RR); + rose_stop_timer(sk); /* HB */ break; } - /* - * Check for frames to transmit. - */ - rose_kick(sk); - break; - - default: break; } - if (sk->protinfo.rose->timer == 0 || --sk->protinfo.rose->timer > 0) { - rose_set_timer(sk); - return; - } + rose_start_heartbeat(sk); +} + +static void rose_timer_expiry(unsigned long param) +{ + struct sock *sk = (struct sock *)param; - /* - * Timer has expired, it may have been T1, T2, T3 or HB. We can tell - * by the socket state. - */ switch (sk->protinfo.rose->state) { - case ROSE_STATE_3: /* HB */ - if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) { - sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; - rose_enquiry_response(sk); - } - break; case ROSE_STATE_1: /* T1 */ case ROSE_STATE_4: /* T2 */ rose_write_internal(sk, ROSE_CLEAR_REQUEST); sk->protinfo.rose->state = ROSE_STATE_2; - sk->protinfo.rose->timer = sk->protinfo.rose->t3; + rose_start_t3timer(sk); break; case ROSE_STATE_2: /* T3 */ - rose_clear_queues(sk); - sk->protinfo.rose->state = ROSE_STATE_0; - sk->state = TCP_CLOSE; - sk->err = ETIMEDOUT; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; + sk->protinfo.rose->neighbour->use--; + rose_disconnect(sk, ETIMEDOUT, -1, -1); + break; + + case ROSE_STATE_3: /* HB */ + if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) { + sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; + rose_enquiry_response(sk); + } break; } +} + +static void rose_idletimer_expiry(unsigned long param) +{ + struct sock *sk = (struct sock *)param; + + rose_clear_queues(sk); + + rose_write_internal(sk, ROSE_CLEAR_REQUEST); + sk->protinfo.rose->state = ROSE_STATE_2; + + rose_start_t3timer(sk); + + sk->state = TCP_CLOSE; + sk->err = 0; + sk->shutdown |= SEND_SHUTDOWN; + + if (!sk->dead) + sk->state_change(sk); - rose_set_timer(sk); + sk->dead = 1; } #endif diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c index 409f79b52..ad45e3b47 100644 --- a/net/rose/sysctl_net_rose.c +++ b/net/rose/sysctl_net_rose.c @@ -11,13 +11,13 @@ #include <net/ax25.h> #include <net/rose.h> -static int min_timer[] = {1 * ROSE_SLOWHZ}; -static int max_timer[] = {300 * ROSE_SLOWHZ}; -static int min_idle[] = {0 * ROSE_SLOWHZ}; -static int max_idle[] = {65535 * ROSE_SLOWHZ}; +static int min_timer[] = {1 * HZ}; +static int max_timer[] = {300 * HZ}; +static int min_idle[] = {0 * HZ}; +static int max_idle[] = {65535 * HZ}; static int min_route[] = {0}, max_route[] = {1}; -static int min_ftimer[] = {60 * ROSE_SLOWHZ}; -static int max_ftimer[] = {600 * ROSE_SLOWHZ}; +static int min_ftimer[] = {60 * HZ}; +static int max_ftimer[] = {600 * HZ}; static int min_maxvcs[] = {1}, max_maxvcs[] = {254}; static int min_window[] = {1}, max_window[] = {7}; |