static void rose_loopback_timer(unsigned long param) { struct sk_buff *skb; struct net_device *dev; rose_address *dest; struct sock *sk; unsigned short frametype; unsigned int lci_i, lci_o; while ((skb = skb_dequeue(&loopback_queue)) != NULL) { lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); frametype = skb->data[2]; dest = (rose_address *)(skb->data + 4); lci_o = 0xFFF - lci_i; skb->h.raw = skb->data; if ((sk = rose_find_socket(lci_o, rose_loopback_neigh)) != NULL) { if (rose_process_rx_frame(sk, skb) == 0) kfree_skb(skb); continue; } if (frametype == ROSE_CALL_REQUEST) { if ((dev = rose_dev_get(dest)) != NULL) { if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) kfree_skb(skb); } else { kfree_skb(skb); } } else { kfree_skb(skb); } } }
static void rose_loopback_timer(unsigned long param) { struct sk_buff *skb; struct net_device *dev; rose_address *dest; struct sock *sk; unsigned short frametype; unsigned int lci_i, lci_o; while ((skb = skb_dequeue(&loopback_queue)) != NULL) { if (skb->len < ROSE_MIN_LEN) { kfree_skb(skb); continue; } lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); frametype = skb->data[2]; if (frametype == ROSE_CALL_REQUEST && (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF || skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] != ROSE_CALL_REQ_ADDR_LEN_VAL)) { kfree_skb(skb); continue; } dest = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF); lci_o = ROSE_DEFAULT_MAXVC + 1 - lci_i; skb_reset_transport_header(skb); sk = rose_find_socket(lci_o, rose_loopback_neigh); if (sk) { if (rose_process_rx_frame(sk, skb) == 0) kfree_skb(skb); continue; } if (frametype == ROSE_CALL_REQUEST) { if ((dev = rose_dev_get(dest)) != NULL) { if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) kfree_skb(skb); } else { kfree_skb(skb); } } else { kfree_skb(skb); } } }
/* * Route a frame to an appropriate AX.25 connection. */ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) { struct rose_neigh *rose_neigh, *new_neigh; struct rose_route *rose_route; struct rose_facilities_struct facilities; rose_address *src_addr, *dest_addr; struct sock *sk; unsigned short frametype; unsigned int lci, new_lci; unsigned char cause, diagnostic; struct net_device *dev; int len, res = 0; #if 0 if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) return res; #endif frametype = skb->data[2]; lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); src_addr = (rose_address *)(skb->data + 9); dest_addr = (rose_address *)(skb->data + 4); spin_lock_bh(&rose_node_list_lock); spin_lock_bh(&rose_neigh_list_lock); spin_lock_bh(&rose_route_list_lock); rose_neigh = rose_neigh_list; while (rose_neigh != NULL) { if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->ax25_dev->dev == rose_neigh->dev) break; rose_neigh = rose_neigh->next; } if (rose_neigh == NULL) { printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->dest_addr)); goto out; } /* * Obviously the link is working, halt the ftimer. */ rose_stop_ftimer(rose_neigh); /* * LCI of zero is always for us, and its always a restart * frame. */ if (lci == 0) { rose_link_rx_restart(skb, rose_neigh, frametype); goto out; } /* * Find an existing socket. */ if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) { if (frametype == ROSE_CALL_REQUEST) { struct rose_sock *rose = rose_sk(sk); /* Remove an existing unused socket */ rose_clear_queues(sk); rose->cause = ROSE_NETWORK_CONGESTION; rose->diagnostic = 0; rose->neighbour->use--; rose->neighbour = NULL; rose->lci = 0; rose->state = ROSE_STATE_0; sk->sk_state = TCP_CLOSE; sk->sk_err = 0; sk->sk_shutdown |= SEND_SHUTDOWN; if (!sock_flag(sk, SOCK_DEAD)) { sk->sk_state_change(sk); sock_set_flag(sk, SOCK_DEAD); } } else { skb->h.raw = skb->data; res = rose_process_rx_frame(sk, skb); goto out; } } /* * Is is a Call Request and is it for us ? */ if (frametype == ROSE_CALL_REQUEST) if ((dev = rose_dev_get(dest_addr)) != NULL) { res = rose_rx_call_request(skb, dev, rose_neigh, lci); dev_put(dev); goto out; } if (!sysctl_rose_routing_control) { rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0); goto out; } /* * Route it to the next in line if we have an entry for it. */ rose_route = rose_route_list; while (rose_route != NULL) { if (rose_route->lci1 == lci && rose_route->neigh1 == rose_neigh) { if (frametype == ROSE_CALL_REQUEST) { /* F6FBB - Remove an existing unused route */ rose_remove_route(rose_route); break; } else if (rose_route->neigh2 != NULL) { skb->data[0] &= 0xF0; skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F; skb->data[1] = (rose_route->lci2 >> 0) & 0xFF; rose_transmit_link(skb, rose_route->neigh2); if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); res = 1; goto out; } else { if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); goto out; } }
/* * Route a frame to an appropriate AX.25 connection. */ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) { struct rose_neigh *rose_neigh, *new_neigh; struct rose_route *rose_route; struct rose_facilities_struct facilities; rose_address *src_addr, *dest_addr; struct sock *sk; unsigned short frametype; unsigned int lci, new_lci; unsigned char cause, diagnostic; struct device *dev; unsigned long flags; int len; struct sk_buff *skbn; #ifdef CONFIG_FIREWALL if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL) != FW_ACCEPT) return 0; #endif frametype = skb->data[2]; lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); src_addr = (rose_address *)(skb->data + 9); dest_addr = (rose_address *)(skb->data + 4); for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->device == rose_neigh->dev) break; if (rose_neigh == NULL) { printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->dest_addr)); return 0; } /* * Obviously the link is working, halt the ftimer. */ rose_neigh->ftimer = 0; /* * LCI of zero is always for us, and its always a restart * frame. */ if (lci == 0) { rose_link_rx_restart(skb, rose_neigh, frametype); return 0; } /* * Find an existing socket. */ if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) { if (frametype == ROSE_CALL_REQUEST) { /* F6FBB - Remove an existing unused socket */ rose_clear_queues(sk); sk->protinfo.rose->cause = ROSE_NETWORK_CONGESTION; sk->protinfo.rose->diagnostic = 0; sk->protinfo.rose->neighbour->use--; sk->protinfo.rose->neighbour = NULL; 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; } else { skb->h.raw = skb->data; return rose_process_rx_frame(sk, skb); } } /* * Is it a Call Request and is it for us ? */ if (frametype == ROSE_CALL_REQUEST) if ((dev = rose_dev_get(dest_addr)) != NULL) { return rose_rx_call_request(skb, dev, rose_neigh, lci); } if (!sysctl_rose_routing_control) { rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0); return 0; } /* * Route it to the next in line if we have an entry for it. */ for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) { if (rose_route->tr1.lci == lci && rose_route->tr1.neigh == rose_neigh) { if (frametype == ROSE_CALL_REQUEST) { /* F6FBB - Remove an existing unused route */ rose_remove_route(rose_route); break; } else if (rose_route->tr2.neigh != NULL) { if ((skbn = skb_copy(skb, GFP_ATOMIC)) != NULL) { kfree_skb(skb, FREE_READ); skb = skbn; } skb->data[0] &= 0xF0; skb->data[0] |= (rose_route->tr2.lci >> 8) & 0x0F; skb->data[1] = (rose_route->tr2.lci >> 0) & 0xFF; rose_transmit_link(skb, rose_route->tr2.neigh); if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); return 1; } else { if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); return 0; } } if (rose_route->tr2.lci == lci && rose_route->tr2.neigh == rose_neigh) { if (frametype == ROSE_CALL_REQUEST) { /* F6FBB - Remove an existing unused route */ rose_remove_route(rose_route); break; } else if (rose_route->tr1.neigh != NULL) { if ((skbn = skb_copy(skb, GFP_ATOMIC)) != NULL) { kfree_skb(skb, FREE_READ); skb = skbn; } skb->data[0] &= 0xF0; skb->data[0] |= (rose_route->tr1.lci >> 8) & 0x0F; skb->data[1] = (rose_route->tr1.lci >> 0) & 0xFF; rose_transmit_link(skb, rose_route->tr1.neigh); if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); return 1; } else { if (frametype == ROSE_CLEAR_CONFIRMATION) rose_remove_route(rose_route); return 0; } }