X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fax25%2Faf_ax25.c;h=a2e0dd047e9f66be4798cd2fadb2cec6d33c498a;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=75ab89d5cb1e360706382a6461df266ff205e62e;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 75ab89d5c..a2e0dd047 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -14,6 +14,7 @@ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) */ #include +#include #include #include #include @@ -45,16 +46,16 @@ #include #include #include -#include +#include #include #include HLIST_HEAD(ax25_list); -spinlock_t ax25_list_lock = SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(ax25_list_lock); -static struct proto_ops ax25_proto_ops; +static const struct proto_ops ax25_proto_ops; static void ax25_free_sock(struct sock *sk) { @@ -180,8 +181,7 @@ struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr, !ax25cmp(&s->dest_addr, dest_addr) && s->sk->sk_type == type) { sk = s->sk; - /* XXX Sleeps with spinlock held, use refcounts instead. XXX */ - lock_sock(sk); + sock_hold(sk); break; } } @@ -228,6 +228,8 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, return NULL; } +EXPORT_SYMBOL(ax25_find_cb); + void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto) { ax25_cb *s; @@ -307,9 +309,7 @@ void ax25_destroy_socket(ax25_cb *ax25) kfree_skb(skb); } - while ((skb = skb_dequeue(&ax25->sk->sk_write_queue)) != NULL) { - kfree_skb(skb); - } + skb_queue_purge(&ax25->sk->sk_write_queue); } if (ax25->sk != NULL) { @@ -336,7 +336,7 @@ void ax25_destroy_socket(ax25_cb *ax25) * includes a KILL command to abort any connection. * VERY useful for debugging ;-) */ -static int ax25_ctl_ioctl(const unsigned int cmd, void *arg) +static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) { struct ax25_ctl_struct ax25_ctl; ax25_digi digi; @@ -426,6 +426,26 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg) return 0; } +static void ax25_fillin_cb_from_dev(ax25_cb *ax25, ax25_dev *ax25_dev) +{ + ax25->rtt = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]) / 2; + ax25->t1 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]); + ax25->t2 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T2]); + ax25->t3 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T3]); + ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; + ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; + ax25->idle = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_IDLE]); + ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; + + if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; + } else { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; + } +} + /* * Fill in a created AX.25 created control block with the default * values for a particular device. @@ -435,39 +455,28 @@ void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev) ax25->ax25_dev = ax25_dev; if (ax25->ax25_dev != NULL) { - ax25->rtt = ax25_dev->values[AX25_VALUES_T1] / 2; - ax25->t1 = ax25_dev->values[AX25_VALUES_T1]; - ax25->t2 = ax25_dev->values[AX25_VALUES_T2]; - ax25->t3 = ax25_dev->values[AX25_VALUES_T3]; - ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; - ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; - ax25->idle = ax25_dev->values[AX25_VALUES_IDLE]; - ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; - - if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; - } + ax25_fillin_cb_from_dev(ax25, ax25_dev); + return; + } + + /* + * No device, use kernel / AX.25 spec default values + */ + ax25->rtt = msecs_to_jiffies(AX25_DEF_T1) / 2; + ax25->t1 = msecs_to_jiffies(AX25_DEF_T1); + ax25->t2 = msecs_to_jiffies(AX25_DEF_T2); + ax25->t3 = msecs_to_jiffies(AX25_DEF_T3); + ax25->n2 = AX25_DEF_N2; + ax25->paclen = AX25_DEF_PACLEN; + ax25->idle = msecs_to_jiffies(AX25_DEF_IDLE); + ax25->backoff = AX25_DEF_BACKOFF; + + if (AX25_DEF_AXDEFMODE) { + ax25->modulus = AX25_EMODULUS; + ax25->window = AX25_DEF_EWINDOW; } else { - ax25->rtt = AX25_DEF_T1 / 2; - ax25->t1 = AX25_DEF_T1; - ax25->t2 = AX25_DEF_T2; - ax25->t3 = AX25_DEF_T3; - ax25->n2 = AX25_DEF_N2; - ax25->paclen = AX25_DEF_PACLEN; - ax25->idle = AX25_DEF_IDLE; - ax25->backoff = AX25_DEF_BACKOFF; - - if (AX25_DEF_AXDEFMODE) { - ax25->modulus = AX25_EMODULUS; - ax25->window = AX25_DEF_EWINDOW; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = AX25_DEF_WINDOW; - } + ax25->modulus = AX25_MODULUS; + ax25->window = AX25_DEF_WINDOW; } } @@ -508,7 +517,7 @@ ax25_cb *ax25_create_cb(void) */ static int ax25_setsockopt(struct socket *sock, int level, int optname, - char *optval, int optlen) + char __user *optval, int optlen) { struct sock *sk = sock->sk; ax25_cb *ax25; @@ -522,7 +531,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, if (optlen < sizeof(int)) return -EINVAL; - if (get_user(opt, (int *)optval)) + if (get_user(opt, (int __user *)optval)) return -EFAULT; lock_sock(sk); @@ -648,7 +657,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, } static int ax25_getsockopt(struct socket *sock, int level, int optname, - char *optval, int *optlen) + char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; ax25_cb *ax25; @@ -763,7 +772,17 @@ out: return res; } -int ax25_create(struct socket *sock, int protocol) +/* + * XXX: when creating ax25_sock we should update the .obj_size setting + * below. + */ +static struct proto ax25_proto = { + .name = "AX25", + .owner = THIS_MODULE, + .obj_size = sizeof(struct sock), +}; + +static int ax25_create(struct socket *sock, int protocol) { struct sock *sk; ax25_cb *ax25; @@ -813,7 +832,7 @@ int ax25_create(struct socket *sock, int protocol) return -ESOCKTNOSUPPORT; } - if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1, NULL)) == NULL) + if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, &ax25_proto, 1)) == NULL) return -ENOMEM; ax25 = sk->sk_protinfo = ax25_create_cb(); @@ -823,7 +842,6 @@ int ax25_create(struct socket *sock, int protocol) } sock_init_data(sock, sk); - sk_set_owner(sk, THIS_MODULE); sk->sk_destruct = ax25_free_sock; sock->ops = &ax25_proto_ops; @@ -839,7 +857,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) struct sock *sk; ax25_cb *ax25, *oax25; - if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1, NULL)) == NULL) + if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) return NULL; if ((ax25 = ax25_create_cb()) == NULL) { @@ -859,7 +877,6 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) } sock_init_data(NULL, sk); - sk_set_owner(sk, THIS_MODULE); sk->sk_destruct = ax25_free_sock; sk->sk_type = osk->sk_type; @@ -868,10 +885,9 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) sk->sk_protocol = osk->sk_protocol; sk->sk_rcvbuf = osk->sk_rcvbuf; sk->sk_sndbuf = osk->sk_sndbuf; - sk->sk_debug = osk->sk_debug; sk->sk_state = TCP_ESTABLISHED; sk->sk_sleep = osk->sk_sleep; - sk->sk_zapped = osk->sk_zapped; + sock_copy_flags(sk, osk); oax25 = ax25_sk(osk); @@ -998,7 +1014,8 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sock *sk = sock->sk; struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; ax25_dev *ax25_dev = NULL; - ax25_address *call; + ax25_uid_assoc *user; + ax25_address call; ax25_cb *ax25; int err = 0; @@ -1017,23 +1034,26 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr->fsa_ax25.sax25_family != AF_AX25) return -EINVAL; - call = ax25_findbyuid(current->euid); - if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) { - return -EACCES; + user = ax25_findbyuid(current->euid); + if (user) { + call = user->call; + ax25_uid_put(user); + } else { + if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) + return -EACCES; + + call = addr->fsa_ax25.sax25_call; } lock_sock(sk); ax25 = ax25_sk(sk); - if (!sk->sk_zapped) { + if (!sock_flag(sk, SOCK_ZAPPED)) { err = -EINVAL; goto out; } - if (call == NULL) - ax25->source_addr = addr->fsa_ax25.sax25_call; - else - ax25->source_addr = *call; + ax25->source_addr = call; /* * User already set interface with SO_BINDTODEVICE @@ -1059,7 +1079,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) done: ax25_cb_add(ax25); - sk->sk_zapped = 0; + sock_reset_flag(sk, SOCK_ZAPPED); out: release_sock(sk); @@ -1130,10 +1150,8 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; - if (ax25->digipeat != NULL) { - kfree(ax25->digipeat); - ax25->digipeat = NULL; - } + kfree(ax25->digipeat); + ax25->digipeat = NULL; /* * Handle digi-peaters to be used. @@ -1172,17 +1190,20 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, * the socket is already bound, check to see if the device has * been filled in, error if it hasn't. */ - if (sk->sk_zapped) { + if (sock_flag(sk, SOCK_ZAPPED)) { /* check if we can remove this feature. It is broken. */ printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n", current->comm); - if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0) + if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0) { + kfree(digi); goto out; + } ax25_fillin_cb(ax25, ax25->ax25_dev); ax25_cb_add(ax25); } else { if (ax25->ax25_dev == NULL) { + kfree(digi); err = -EHOSTUNREACH; goto out; } @@ -1191,8 +1212,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, if (sk->sk_type == SOCK_SEQPACKET && (ax25t=ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, ax25->ax25_dev->dev))) { - if (digi != NULL) - kfree(digi); + kfree(digi); err = -EADDRINUSE; /* Already such a connection */ ax25_cb_put(ax25t); goto out; @@ -1336,7 +1356,6 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) remove_wait_queue(sk->sk_sleep, &wait); newsk = skb->sk; - newsk->sk_pair = NULL; newsk->sk_socket = newsock; newsk->sk_sleep = &newsock->wait; @@ -1413,14 +1432,13 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, size_t size; int lv, err, addr_len = msg->msg_namelen; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) { + if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) return -EINVAL; - } lock_sock(sk); ax25 = ax25_sk(sk); - if (sk->sk_zapped) { + if (sock_flag(sk, SOCK_ZAPPED)) { err = -EADDRNOTAVAIL; goto out; } @@ -1578,9 +1596,7 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, *asmptr = AX25_UI; /* Datagram frames go straight out of the door as UI */ - skb->dev = ax25->ax25_dev->dev; - - ax25_queue_xmit(skb); + ax25_queue_xmit(skb, ax25->ax25_dev->dev); err = len; @@ -1669,6 +1685,7 @@ static int ax25_shutdown(struct socket *sk, int how) static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; + void __user *argp = (void __user *)arg; int res = 0; lock_sock(sk); @@ -1678,7 +1695,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; - res = put_user(amount, (int *)arg); + res = put_user(amount, (int __user *)argp); break; } @@ -1688,23 +1705,19 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; - res = put_user(amount, (int *)arg); + res = put_user(amount, (int __user *) argp); break; } case SIOCGSTAMP: - if (sk != NULL) { - res = sock_get_timestamp(sk, (struct timeval *)arg); - break; - } - res = -EINVAL; + res = sock_get_timestamp(sk, argp); break; case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */ case SIOCAX25GETUID: { struct sockaddr_ax25 sax25; - if (copy_from_user(&sax25, (void *)arg, sizeof(sax25))) { + if (copy_from_user(&sax25, argp, sizeof(sax25))) { res = -EFAULT; break; } @@ -1718,7 +1731,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = -EPERM; break; } - if (get_user(amount, (long *)arg)) { + if (get_user(amount, (long __user *)argp)) { res = -EFAULT; break; } @@ -1738,7 +1751,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = -EPERM; break; } - res = ax25_rt_ioctl(cmd, (void *)arg); + res = ax25_rt_ioctl(cmd, argp); break; case SIOCAX25CTLCON: @@ -1746,7 +1759,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = -EPERM; break; } - res = ax25_ctl_ioctl(cmd, (void *)arg); + res = ax25_ctl_ioctl(cmd, argp); break; case SIOCAX25GETINFO: @@ -1783,12 +1796,12 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) warned=1; } - if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_deprecated))) { + if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct_deprecated))) { res = -EFAULT; break; } } else { - if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) { + if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct))) { res = -EINVAL; break; } @@ -1804,7 +1817,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = -EPERM; break; } - if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) { + if (copy_from_user(&ax25_fwd, argp, sizeof(ax25_fwd))) { res = -EFAULT; break; } @@ -1826,7 +1839,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; default: - res = dev_ioctl(cmd, (void *)arg); + res = -ENOIOCTLCMD; break; } release_sock(sk); @@ -1867,6 +1880,7 @@ static void ax25_info_stop(struct seq_file *seq, void *v) static int ax25_info_show(struct seq_file *seq, void *v) { ax25_cb *ax25 = v; + char buf[11]; int k; @@ -1878,13 +1892,13 @@ static int ax25_info_show(struct seq_file *seq, void *v) seq_printf(seq, "%8.8lx %s %s%s ", (long) ax25, ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, - ax2asc(&ax25->source_addr), + ax2asc(buf, &ax25->source_addr), ax25->iamdigi? "*":""); - seq_printf(seq, "%s", ax2asc(&ax25->dest_addr)); + seq_printf(seq, "%s", ax2asc(buf, &ax25->dest_addr)); for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { seq_printf(seq, ",%s%s", - ax2asc(&ax25->digipeat->calls[k]), + ax2asc(buf, &ax25->digipeat->calls[k]), ax25->digipeat->repeated[k]? "*":""); } @@ -1942,25 +1956,25 @@ static struct net_proto_family ax25_family_ops = { .owner = THIS_MODULE, }; -static struct proto_ops ax25_proto_ops = { - .family = PF_AX25, - .owner = THIS_MODULE, - .release = ax25_release, - .bind = ax25_bind, - .connect = ax25_connect, - .socketpair = sock_no_socketpair, - .accept = ax25_accept, - .getname = ax25_getname, - .poll = datagram_poll, - .ioctl = ax25_ioctl, - .listen = ax25_listen, - .shutdown = ax25_shutdown, - .setsockopt = ax25_setsockopt, - .getsockopt = ax25_getsockopt, - .sendmsg = ax25_sendmsg, - .recvmsg = ax25_recvmsg, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, +static const struct proto_ops ax25_proto_ops = { + .family = PF_AX25, + .owner = THIS_MODULE, + .release = ax25_release, + .bind = ax25_bind, + .connect = ax25_connect, + .socketpair = sock_no_socketpair, + .accept = ax25_accept, + .getname = ax25_getname, + .poll = datagram_poll, + .ioctl = ax25_ioctl, + .listen = ax25_listen, + .shutdown = ax25_shutdown, + .setsockopt = ax25_setsockopt, + .getsockopt = ax25_getsockopt, + .sendmsg = ax25_sendmsg, + .recvmsg = ax25_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, }; /* @@ -1976,26 +1990,13 @@ static struct notifier_block ax25_dev_notifier = { .notifier_call =ax25_device_event, }; -EXPORT_SYMBOL(ax25_encapsulate); -EXPORT_SYMBOL(ax25_rebuild_header); -EXPORT_SYMBOL(ax25_findbyuid); -EXPORT_SYMBOL(ax25_find_cb); -EXPORT_SYMBOL(ax25_linkfail_register); -EXPORT_SYMBOL(ax25_linkfail_release); -EXPORT_SYMBOL(ax25_listen_register); -EXPORT_SYMBOL(ax25_listen_release); -EXPORT_SYMBOL(ax25_protocol_register); -EXPORT_SYMBOL(ax25_protocol_release); -EXPORT_SYMBOL(ax25_send_frame); -EXPORT_SYMBOL(ax25_uid_policy); -EXPORT_SYMBOL(ax25cmp); -EXPORT_SYMBOL(ax2asc); -EXPORT_SYMBOL(asc2ax); -EXPORT_SYMBOL(null_ax25_address); -EXPORT_SYMBOL(ax25_display_timer); - static int __init ax25_init(void) { + int rc = proto_register(&ax25_proto, 0); + + if (rc != 0) + goto out; + sock_register(&ax25_family_ops); dev_add_pack(&ax25_packet_type); register_netdevice_notifier(&ax25_dev_notifier); @@ -2004,8 +2005,8 @@ static int __init ax25_init(void) proc_net_fops_create("ax25_route", S_IRUGO, &ax25_route_fops); proc_net_fops_create("ax25", S_IRUGO, &ax25_info_fops); proc_net_fops_create("ax25_calls", S_IRUGO, &ax25_uid_fops); - - return 0; +out: + return rc; } module_init(ax25_init); @@ -2030,5 +2031,6 @@ static void __exit ax25_exit(void) dev_remove_pack(&ax25_packet_type); sock_unregister(PF_AX25); + proto_unregister(&ax25_proto); } module_exit(ax25_exit);