diff options
Diffstat (limited to 'net/x25/af_x25.c')
-rw-r--r-- | net/x25/af_x25.c | 135 |
1 files changed, 104 insertions, 31 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index e3219e4cd044..5e86d4e97dce 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -47,6 +47,7 @@ #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/skbuff.h> +#include <linux/slab.h> #include <net/sock.h> #include <net/tcp_states.h> #include <asm/uaccess.h> @@ -55,6 +56,7 @@ #include <linux/notifier.h> #include <linux/init.h> #include <linux/compat.h> +#include <linux/ctype.h> #include <net/x25.h> #include <net/compat.h> @@ -81,6 +83,41 @@ struct compat_x25_subscrip_struct { }; #endif + +int x25_parse_address_block(struct sk_buff *skb, + struct x25_address *called_addr, + struct x25_address *calling_addr) +{ + unsigned char len; + int needed; + int rc; + + if (skb->len < 1) { + /* packet has no address block */ + rc = 0; + goto empty; + } + + len = *skb->data; + needed = 1 + (len >> 4) + (len & 0x0f); + + if (skb->len < needed) { + /* packet is too short to hold the addresses it claims + to hold */ + rc = -1; + goto empty; + } + + return x25_addr_ntoa(skb->data, called_addr, calling_addr); + +empty: + *called_addr->x25_addr = 0; + *calling_addr->x25_addr = 0; + + return rc; +} + + int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr, struct x25_address *calling_addr) { @@ -365,6 +402,7 @@ static void __x25_destroy_socket(struct sock *sk) /* * Queue the unaccepted socket for death */ + skb->sk->sk_state = TCP_LISTEN; sock_set_flag(skb->sk, SOCK_DEAD); x25_start_heartbeat(skb->sk); x25_sk(skb->sk)->state = X25_STATE_0; @@ -415,7 +453,6 @@ static int x25_setsockopt(struct socket *sock, int level, int optname, struct sock *sk = sock->sk; int rc = -ENOPROTOOPT; - lock_kernel(); if (level != SOL_X25 || optname != X25_QBITINCL) goto out; @@ -427,10 +464,12 @@ static int x25_setsockopt(struct socket *sock, int level, int optname, if (get_user(opt, (int __user *)optval)) goto out; - x25_sk(sk)->qbitincl = !!opt; + if (opt) + set_bit(X25_Q_BIT_FLAG, &x25_sk(sk)->flags); + else + clear_bit(X25_Q_BIT_FLAG, &x25_sk(sk)->flags); rc = 0; out: - unlock_kernel(); return rc; } @@ -440,7 +479,6 @@ static int x25_getsockopt(struct socket *sock, int level, int optname, struct sock *sk = sock->sk; int val, len, rc = -ENOPROTOOPT; - lock_kernel(); if (level != SOL_X25 || optname != X25_QBITINCL) goto out; @@ -458,10 +496,9 @@ static int x25_getsockopt(struct socket *sock, int level, int optname, if (put_user(len, optlen)) goto out; - val = x25_sk(sk)->qbitincl; + val = test_bit(X25_Q_BIT_FLAG, &x25_sk(sk)->flags); rc = copy_to_user(optval, &val, len) ? -EFAULT : 0; out: - unlock_kernel(); return rc; } @@ -512,15 +549,20 @@ static int x25_create(struct net *net, struct socket *sock, int protocol, { struct sock *sk; struct x25_sock *x25; - int rc = -ESOCKTNOSUPPORT; + int rc = -EAFNOSUPPORT; if (!net_eq(net, &init_net)) - return -EAFNOSUPPORT; + goto out; - if (sock->type != SOCK_SEQPACKET || protocol) + rc = -ESOCKTNOSUPPORT; + if (sock->type != SOCK_SEQPACKET) goto out; - rc = -ENOMEM; + rc = -EINVAL; + if (protocol) + goto out; + + rc = -ENOBUFS; if ((sk = x25_alloc_socket(net)) == NULL) goto out; @@ -540,14 +582,15 @@ static int x25_create(struct net *net, struct socket *sock, int protocol, x25->t2 = sysctl_x25_ack_holdback_timeout; x25->state = X25_STATE_0; x25->cudmatchlength = 0; - x25->accptapprv = X25_DENY_ACCPT_APPRV; /* normally no cud */ + set_bit(X25_ACCPT_APPRV_FLAG, &x25->flags); /* normally no cud */ /* on call accept */ x25->facilities.winsize_in = X25_DEFAULT_WINDOW_SIZE; x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE; x25->facilities.pacsize_in = X25_DEFAULT_PACKET_SIZE; x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; - x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; + x25->facilities.throughput = 0; /* by default don't negotiate + throughput */ x25->facilities.reverse = X25_DEFAULT_REVERSE; x25->dte_facilities.calling_len = 0; x25->dte_facilities.called_len = 0; @@ -588,12 +631,12 @@ static struct sock *x25_make_new(struct sock *osk) x25->t22 = ox25->t22; x25->t23 = ox25->t23; x25->t2 = ox25->t2; + x25->flags = ox25->flags; x25->facilities = ox25->facilities; - x25->qbitincl = ox25->qbitincl; x25->dte_facilities = ox25->dte_facilities; x25->cudmatchlength = ox25->cudmatchlength; - x25->accptapprv = ox25->accptapprv; + clear_bit(X25_INTERRUPT_FLAG, &x25->flags); x25_init_timers(sk); out: return sk; @@ -643,7 +686,7 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk = sock->sk; struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; - int rc = 0; + int len, i, rc = 0; lock_kernel(); if (!sock_flag(sk, SOCK_ZAPPED) || @@ -653,6 +696,14 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) goto out; } + len = strlen(addr->sx25_addr.x25_addr); + for (i = 0; i < len; i++) { + if (!isdigit(addr->sx25_addr.x25_addr[i])) { + rc = -EINVAL; + goto out; + } + } + x25_sk(sk)->source_addr = addr->sx25_addr; x25_insert_socket(sk); sock_reset_flag(sk, SOCK_ZAPPED); @@ -667,7 +718,7 @@ static int x25_wait_for_connection_establishment(struct sock *sk) DECLARE_WAITQUEUE(wait, current); int rc; - add_wait_queue_exclusive(sk->sk_sleep, &wait); + add_wait_queue_exclusive(sk_sleep(sk), &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); rc = -ERESTARTSYS; @@ -687,7 +738,7 @@ static int x25_wait_for_connection_establishment(struct sock *sk) break; } __set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sk_sleep, &wait); + remove_wait_queue(sk_sleep(sk), &wait); return rc; } @@ -787,7 +838,7 @@ static int x25_wait_for_data(struct sock *sk, long timeout) DECLARE_WAITQUEUE(wait, current); int rc = 0; - add_wait_queue_exclusive(sk->sk_sleep, &wait); + add_wait_queue_exclusive(sk_sleep(sk), &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); if (sk->sk_shutdown & RCV_SHUTDOWN) @@ -807,7 +858,7 @@ static int x25_wait_for_data(struct sock *sk, long timeout) break; } __set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sk_sleep, &wait); + remove_wait_queue(sk_sleep(sk), &wait); return rc; } @@ -907,16 +958,26 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, /* * Extract the X.25 addresses and convert them to ASCII strings, * and remove them. + * + * Address block is mandatory in call request packets */ - addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr); + addr_len = x25_parse_address_block(skb, &source_addr, &dest_addr); + if (addr_len <= 0) + goto out_clear_request; skb_pull(skb, addr_len); /* * Get the length of the facilities, skip past them for the moment * get the call user data because this is needed to determine * the correct listener + * + * Facilities length is mandatory in call request packets */ + if (skb->len < 1) + goto out_clear_request; len = skb->data[0] + 1; + if (skb->len < len) + goto out_clear_request; skb_pull(skb,len); /* @@ -991,8 +1052,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE; makex25->cudmatchlength = x25_sk(sk)->cudmatchlength; - /* Normally all calls are accepted immediatly */ - if(makex25->accptapprv & X25_DENY_ACCPT_APPRV) { + /* Normally all calls are accepted immediately */ + if (test_bit(X25_ACCPT_APPRV_FLAG, &makex25->flags)) { x25_write_internal(make, X25_CALL_ACCEPTED); makex25->state = X25_STATE_3; } @@ -1124,7 +1185,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, * If the Q BIT Include socket option is in force, the first * byte of the user data is the logical value of the Q Bit. */ - if (x25->qbitincl) { + if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { qbit = skb->data[0]; skb_pull(skb, 1); } @@ -1180,7 +1241,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, len = rc; if (rc < 0) kfree_skb(skb); - else if (x25->qbitincl) + else if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) len++; } @@ -1245,7 +1306,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, /* * No Q bit information on Interrupt data. */ - if (x25->qbitincl) { + if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { asmptr = skb_push(skb, 1); *asmptr = 0x00; } @@ -1263,7 +1324,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, skb_pull(skb, x25->neighbour->extended ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN); - if (x25->qbitincl) { + if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { asmptr = skb_push(skb, 1); *asmptr = qbit; } @@ -1400,9 +1461,20 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (facilities.winsize_in < 1 || facilities.winsize_in > 127) break; - if (facilities.throughput < 0x03 || - facilities.throughput > 0xDD) - break; + if (facilities.throughput) { + int out = facilities.throughput & 0xf0; + int in = facilities.throughput & 0x0f; + if (!out) + facilities.throughput |= + X25_DEFAULT_THROUGHPUT << 4; + else if (out < 0x30 || out > 0xD0) + break; + if (!in) + facilities.throughput |= + X25_DEFAULT_THROUGHPUT; + else if (in < 0x03 || in > 0x0D) + break; + } if (facilities.reverse && (facilities.reverse & 0x81) != 0x81) break; @@ -1503,7 +1575,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) rc = -EINVAL; if (sk->sk_state != TCP_CLOSE) break; - x25->accptapprv = X25_ALLOW_ACCPT_APPRV; + clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags); rc = 0; break; } @@ -1512,7 +1584,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) rc = -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) break; - if (x25->accptapprv) /* must call accptapprv above */ + /* must call accptapprv above */ + if (test_bit(X25_ACCPT_APPRV_FLAG, &x25->flags)) break; x25_write_internal(sk, X25_CALL_ACCEPTED); x25->state = X25_STATE_3; |