|
@@ -270,6 +270,28 @@ static int rds_cong_monitor(struct rds_sock *rs, char __user *optval,
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int rds_set_transport(struct rds_sock *rs, char __user *optval,
|
|
|
|
+ int optlen)
|
|
|
|
+{
|
|
|
|
+ int t_type;
|
|
|
|
+
|
|
|
|
+ if (rs->rs_transport)
|
|
|
|
+ return -EOPNOTSUPP; /* previously attached to transport */
|
|
|
|
+
|
|
|
|
+ if (optlen != sizeof(int))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if (copy_from_user(&t_type, (int __user *)optval, sizeof(t_type)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ if (t_type < 0 || t_type >= RDS_TRANS_COUNT)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ rs->rs_transport = rds_trans_get(t_type);
|
|
|
|
+
|
|
|
|
+ return rs->rs_transport ? 0 : -ENOPROTOOPT;
|
|
|
|
+}
|
|
|
|
+
|
|
static int rds_setsockopt(struct socket *sock, int level, int optname,
|
|
static int rds_setsockopt(struct socket *sock, int level, int optname,
|
|
char __user *optval, unsigned int optlen)
|
|
char __user *optval, unsigned int optlen)
|
|
{
|
|
{
|
|
@@ -300,6 +322,11 @@ static int rds_setsockopt(struct socket *sock, int level, int optname,
|
|
case RDS_CONG_MONITOR:
|
|
case RDS_CONG_MONITOR:
|
|
ret = rds_cong_monitor(rs, optval, optlen);
|
|
ret = rds_cong_monitor(rs, optval, optlen);
|
|
break;
|
|
break;
|
|
|
|
+ case SO_RDS_TRANSPORT:
|
|
|
|
+ lock_sock(sock->sk);
|
|
|
|
+ ret = rds_set_transport(rs, optval, optlen);
|
|
|
|
+ release_sock(sock->sk);
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
ret = -ENOPROTOOPT;
|
|
ret = -ENOPROTOOPT;
|
|
}
|
|
}
|
|
@@ -312,6 +339,7 @@ static int rds_getsockopt(struct socket *sock, int level, int optname,
|
|
{
|
|
{
|
|
struct rds_sock *rs = rds_sk_to_rs(sock->sk);
|
|
struct rds_sock *rs = rds_sk_to_rs(sock->sk);
|
|
int ret = -ENOPROTOOPT, len;
|
|
int ret = -ENOPROTOOPT, len;
|
|
|
|
+ int trans;
|
|
|
|
|
|
if (level != SOL_RDS)
|
|
if (level != SOL_RDS)
|
|
goto out;
|
|
goto out;
|
|
@@ -337,6 +365,19 @@ static int rds_getsockopt(struct socket *sock, int level, int optname,
|
|
else
|
|
else
|
|
ret = 0;
|
|
ret = 0;
|
|
break;
|
|
break;
|
|
|
|
+ case SO_RDS_TRANSPORT:
|
|
|
|
+ if (len < sizeof(int)) {
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ trans = (rs->rs_transport ? rs->rs_transport->t_type :
|
|
|
|
+ RDS_TRANS_NONE); /* unbound */
|
|
|
|
+ if (put_user(trans, (int __user *)optval) ||
|
|
|
|
+ put_user(sizeof(int), optlen))
|
|
|
|
+ ret = -EFAULT;
|
|
|
|
+ else
|
|
|
|
+ ret = 0;
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
break;
|
|
break;
|
|
}
|
|
}
|