diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 50 |
1 files changed, 19 insertions, 31 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index a998b6a9c245..2533f5cf2e4b 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -1052,20 +1052,15 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
1052 | return err; | 1052 | return err; |
1053 | } | 1053 | } |
1054 | 1054 | ||
1055 | static int tun_get_iff(struct net *net, struct file *file, struct ifreq *ifr) | 1055 | static int tun_get_iff(struct net *net, struct tun_struct *tun, |
1056 | struct ifreq *ifr) | ||
1056 | { | 1057 | { |
1057 | struct tun_struct *tun = tun_get(file); | ||
1058 | |||
1059 | if (!tun) | ||
1060 | return -EBADFD; | ||
1061 | |||
1062 | DBG(KERN_INFO "%s: tun_get_iff\n", tun->dev->name); | 1058 | DBG(KERN_INFO "%s: tun_get_iff\n", tun->dev->name); |
1063 | 1059 | ||
1064 | strcpy(ifr->ifr_name, tun->dev->name); | 1060 | strcpy(ifr->ifr_name, tun->dev->name); |
1065 | 1061 | ||
1066 | ifr->ifr_flags = tun_flags(tun); | 1062 | ifr->ifr_flags = tun_flags(tun); |
1067 | 1063 | ||
1068 | tun_put(tun); | ||
1069 | return 0; | 1064 | return 0; |
1070 | } | 1065 | } |
1071 | 1066 | ||
@@ -1115,8 +1110,8 @@ static int set_offload(struct net_device *dev, unsigned long arg) | |||
1115 | return 0; | 1110 | return 0; |
1116 | } | 1111 | } |
1117 | 1112 | ||
1118 | static int tun_chr_ioctl(struct inode *inode, struct file *file, | 1113 | static long tun_chr_ioctl(struct file *file, unsigned int cmd, |
1119 | unsigned int cmd, unsigned long arg) | 1114 | unsigned long arg) |
1120 | { | 1115 | { |
1121 | struct tun_file *tfile = file->private_data; | 1116 | struct tun_file *tfile = file->private_data; |
1122 | struct tun_struct *tun; | 1117 | struct tun_struct *tun; |
@@ -1138,34 +1133,32 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
1138 | (unsigned int __user*)argp); | 1133 | (unsigned int __user*)argp); |
1139 | } | 1134 | } |
1140 | 1135 | ||
1136 | rtnl_lock(); | ||
1137 | |||
1141 | tun = __tun_get(tfile); | 1138 | tun = __tun_get(tfile); |
1142 | if (cmd == TUNSETIFF && !tun) { | 1139 | if (cmd == TUNSETIFF && !tun) { |
1143 | int err; | ||
1144 | |||
1145 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; | 1140 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; |
1146 | 1141 | ||
1147 | rtnl_lock(); | 1142 | ret = tun_set_iff(tfile->net, file, &ifr); |
1148 | err = tun_set_iff(tfile->net, file, &ifr); | ||
1149 | rtnl_unlock(); | ||
1150 | 1143 | ||
1151 | if (err) | 1144 | if (ret) |
1152 | return err; | 1145 | goto unlock; |
1153 | 1146 | ||
1154 | if (copy_to_user(argp, &ifr, sizeof(ifr))) | 1147 | if (copy_to_user(argp, &ifr, sizeof(ifr))) |
1155 | return -EFAULT; | 1148 | ret = -EFAULT; |
1156 | return 0; | 1149 | goto unlock; |
1157 | } | 1150 | } |
1158 | 1151 | ||
1159 | 1152 | ret = -EBADFD; | |
1160 | if (!tun) | 1153 | if (!tun) |
1161 | return -EBADFD; | 1154 | goto unlock; |
1162 | 1155 | ||
1163 | DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd); | 1156 | DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd); |
1164 | 1157 | ||
1165 | ret = 0; | 1158 | ret = 0; |
1166 | switch (cmd) { | 1159 | switch (cmd) { |
1167 | case TUNGETIFF: | 1160 | case TUNGETIFF: |
1168 | ret = tun_get_iff(current->nsproxy->net_ns, file, &ifr); | 1161 | ret = tun_get_iff(current->nsproxy->net_ns, tun, &ifr); |
1169 | if (ret) | 1162 | if (ret) |
1170 | break; | 1163 | break; |
1171 | 1164 | ||
@@ -1211,7 +1204,6 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
1211 | 1204 | ||
1212 | case TUNSETLINK: | 1205 | case TUNSETLINK: |
1213 | /* Only allow setting the type when the interface is down */ | 1206 | /* Only allow setting the type when the interface is down */ |
1214 | rtnl_lock(); | ||
1215 | if (tun->dev->flags & IFF_UP) { | 1207 | if (tun->dev->flags & IFF_UP) { |
1216 | DBG(KERN_INFO "%s: Linktype set failed because interface is up\n", | 1208 | DBG(KERN_INFO "%s: Linktype set failed because interface is up\n", |
1217 | tun->dev->name); | 1209 | tun->dev->name); |
@@ -1221,7 +1213,6 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
1221 | DBG(KERN_INFO "%s: linktype set to %d\n", tun->dev->name, tun->dev->type); | 1213 | DBG(KERN_INFO "%s: linktype set to %d\n", tun->dev->name, tun->dev->type); |
1222 | ret = 0; | 1214 | ret = 0; |
1223 | } | 1215 | } |
1224 | rtnl_unlock(); | ||
1225 | break; | 1216 | break; |
1226 | 1217 | ||
1227 | #ifdef TUN_DEBUG | 1218 | #ifdef TUN_DEBUG |
@@ -1230,9 +1221,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
1230 | break; | 1221 | break; |
1231 | #endif | 1222 | #endif |
1232 | case TUNSETOFFLOAD: | 1223 | case TUNSETOFFLOAD: |
1233 | rtnl_lock(); | ||
1234 | ret = set_offload(tun->dev, arg); | 1224 | ret = set_offload(tun->dev, arg); |
1235 | rtnl_unlock(); | ||
1236 | break; | 1225 | break; |
1237 | 1226 | ||
1238 | case TUNSETTXFILTER: | 1227 | case TUNSETTXFILTER: |
@@ -1240,9 +1229,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
1240 | ret = -EINVAL; | 1229 | ret = -EINVAL; |
1241 | if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) | 1230 | if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) |
1242 | break; | 1231 | break; |
1243 | rtnl_lock(); | ||
1244 | ret = update_filter(&tun->txflt, (void __user *)arg); | 1232 | ret = update_filter(&tun->txflt, (void __user *)arg); |
1245 | rtnl_unlock(); | ||
1246 | break; | 1233 | break; |
1247 | 1234 | ||
1248 | case SIOCGIFHWADDR: | 1235 | case SIOCGIFHWADDR: |
@@ -1258,9 +1245,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
1258 | DBG(KERN_DEBUG "%s: set hw address: %pM\n", | 1245 | DBG(KERN_DEBUG "%s: set hw address: %pM\n", |
1259 | tun->dev->name, ifr.ifr_hwaddr.sa_data); | 1246 | tun->dev->name, ifr.ifr_hwaddr.sa_data); |
1260 | 1247 | ||
1261 | rtnl_lock(); | ||
1262 | ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); | 1248 | ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); |
1263 | rtnl_unlock(); | ||
1264 | break; | 1249 | break; |
1265 | 1250 | ||
1266 | case TUNGETSNDBUF: | 1251 | case TUNGETSNDBUF: |
@@ -1283,7 +1268,10 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
1283 | break; | 1268 | break; |
1284 | }; | 1269 | }; |
1285 | 1270 | ||
1286 | tun_put(tun); | 1271 | unlock: |
1272 | rtnl_unlock(); | ||
1273 | if (tun) | ||
1274 | tun_put(tun); | ||
1287 | return ret; | 1275 | return ret; |
1288 | } | 1276 | } |
1289 | 1277 | ||
@@ -1371,7 +1359,7 @@ static const struct file_operations tun_fops = { | |||
1371 | .write = do_sync_write, | 1359 | .write = do_sync_write, |
1372 | .aio_write = tun_chr_aio_write, | 1360 | .aio_write = tun_chr_aio_write, |
1373 | .poll = tun_chr_poll, | 1361 | .poll = tun_chr_poll, |
1374 | .ioctl = tun_chr_ioctl, | 1362 | .unlocked_ioctl = tun_chr_ioctl, |
1375 | .open = tun_chr_open, | 1363 | .open = tun_chr_open, |
1376 | .release = tun_chr_close, | 1364 | .release = tun_chr_close, |
1377 | .fasync = tun_chr_fasync | 1365 | .fasync = tun_chr_fasync |