diff -ruN -X dontdiff linux-2.4.18-rc2/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- linux-2.4.18-rc2/net/netrom/af_netrom.c Tue Feb 19 16:06:42 2002 +++ linux/net/netrom/af_netrom.c Tue Feb 19 16:14:39 2002 @@ -31,7 +31,9 @@ * NET/ROM 007 Jonathan(G4KLX) New timer architecture. * Impmented Idle timer. * Arnaldo C. Melo s/suser/capable/, micro cleanups - * Jeroen (PE1RXQ) Use sock_orphan() on release. + * Jeroen(PE1RXQ) Use sock_orphan() on release. + * Tomi(OH2BNS) Better frame type checking. + * Device refcnt fixes. */ #include @@ -128,6 +130,7 @@ if ((s = nr_list) == sk) { nr_list = s->next; + dev_put(sk->protinfo.nr->device); restore_flags(flags); return; } @@ -135,6 +138,7 @@ while (s != NULL && s->next != NULL) { if (s->next == sk) { s->next = sk->next; + dev_put(sk->protinfo.nr->device); restore_flags(flags); return; } @@ -616,16 +620,20 @@ * Only the super user can set an arbitrary user callsign. */ if (addr->fsa_ax25.sax25_ndigis == 1) { - if (!capable(CAP_NET_BIND_SERVICE)) + if (!capable(CAP_NET_BIND_SERVICE)) { + dev_put(dev); return -EACCES; + } sk->protinfo.nr->user_addr = addr->fsa_digipeater[0]; sk->protinfo.nr->source_addr = addr->fsa_ax25.sax25_call; } else { source = &addr->fsa_ax25.sax25_call; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) + if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { + dev_put(dev); return -EPERM; + } user = source; } @@ -680,8 +688,10 @@ source = (ax25_address *)dev->dev_addr; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) + if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) { + dev_put(dev); return -EPERM; + } user = source; } @@ -976,6 +986,8 @@ sk->ack_backlog++; make->pair = sk; + dev_hold(make->protinfo.nr->device); + nr_insert_socket(make); skb_queue_head(&sk->receive_queue, skb); @@ -1364,7 +1376,6 @@ dev_nr[i].priv = NULL; unregister_netdev(&dev_nr[i]); } - kfree(dev_nr[i].name); } kfree(dev_nr); diff -ruN -X dontdiff linux-2.4.18-rc2/net/netrom/nr_loopback.c linux/net/netrom/nr_loopback.c --- linux-2.4.18-rc2/net/netrom/nr_loopback.c Thu Jun 28 03:10:55 2001 +++ linux/net/netrom/nr_loopback.c Tue Feb 19 16:12:35 2002 @@ -85,6 +85,9 @@ if (dev == NULL || nr_rx_frame(skb, dev) == 0) kfree_skb(skb); + if (dev != NULL) + dev_put(dev); + if (!skb_queue_empty(&loopback_queue) && !nr_loopback_running()) nr_set_loopback_timer(); } diff -ruN -X dontdiff linux-2.4.18-rc2/net/netrom/nr_route.c linux/net/netrom/nr_route.c --- linux-2.4.18-rc2/net/netrom/nr_route.c Sat Dec 30 00:44:46 2000 +++ linux/net/netrom/nr_route.c Tue Feb 19 16:12:35 2002 @@ -19,6 +19,7 @@ * Alan Cox(GW4PTS) Added the firewall hooks. * NET/ROM 006 Jonathan(G4KLX) Added the setting of digipeated neighbours. * Tomi(OH2BNS) Routing quality and link failure changes. + * Device refcnt fixes. */ #include @@ -66,11 +67,15 @@ struct nr_node *nr_node; struct nr_neigh *nr_neigh; struct nr_route nr_route; + struct net_device *tdev; unsigned long flags; int i, found; - if (nr_dev_get(nr) != NULL) /* Can't add routes to ourself */ + /* Can't add routes to ourself */ + if ((tdev = nr_dev_get(nr)) != NULL) { + dev_put(tdev); return -EINVAL; + } for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) if (ax25cmp(nr, &nr_node->callsign) == 0) @@ -124,6 +129,8 @@ memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi)); } + dev_hold(nr_neigh->dev); + save_flags(flags); cli(); @@ -294,6 +301,7 @@ if ((s = nr_neigh_list) == nr_neigh) { nr_neigh_list = nr_neigh->next; restore_flags(flags); + dev_put(nr_neigh->dev); if (nr_neigh->digipeat != NULL) kfree(nr_neigh->digipeat); kfree(nr_neigh); @@ -304,6 +312,7 @@ if (s->next == nr_neigh) { s->next = nr_neigh->next; restore_flags(flags); + dev_put(nr_neigh->dev); if (nr_neigh->digipeat != NULL) kfree(nr_neigh->digipeat); kfree(nr_neigh); @@ -404,6 +413,8 @@ memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi)); } + dev_hold(nr_neigh->dev); + save_flags(flags); cli(); @@ -570,6 +581,10 @@ if (first == NULL || strncmp(dev->name, first->name, 3) < 0) first = dev; } + + if (first != NULL) + dev_hold(first); + read_unlock(&dev_base_lock); return first; @@ -620,6 +635,7 @@ { struct nr_route_struct nr_route; struct net_device *dev; + int ret; switch (cmd) { @@ -628,23 +644,30 @@ 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) + if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) { + dev_put(dev); return -EINVAL; + } switch (nr_route.type) { case NETROM_NODE: - return nr_add_node(&nr_route.callsign, + ret = nr_add_node(&nr_route.callsign, nr_route.mnemonic, &nr_route.neighbour, nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), dev, nr_route.quality, nr_route.obs_count); + break; case NETROM_NEIGH: - return nr_add_neigh(&nr_route.callsign, + ret = nr_add_neigh(&nr_route.callsign, nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), dev, nr_route.quality); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + dev_put(dev); + return ret; case SIOCDELRT: if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) @@ -653,14 +676,19 @@ return -EINVAL; switch (nr_route.type) { case NETROM_NODE: - return nr_del_node(&nr_route.callsign, + ret = nr_del_node(&nr_route.callsign, &nr_route.neighbour, dev); + break; case NETROM_NEIGH: - return nr_del_neigh(&nr_route.callsign, + ret = nr_del_neigh(&nr_route.callsign, dev, nr_route.quality); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + dev_put(dev); + return ret; case SIOCNRDECOBS: return nr_dec_obs(); @@ -717,10 +745,15 @@ ax25->ax25_dev->dev, 0, sysctl_netrom_obsolescence_count_initialiser); if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */ + int ret; + if (ax25 == NULL) /* Its from me */ - return nr_loopback_queue(skb); + ret = nr_loopback_queue(skb); else - return nr_rx_frame(skb, dev); + ret = nr_rx_frame(skb, dev); + + dev_put(dev); + return ret; } if (!sysctl_netrom_routing_control && ax25 != NULL) @@ -747,6 +780,8 @@ nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); + dev_put(dev); + return (nr_neigh->ax25 != NULL); }