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 027f7aba26af..42b6c6319bc2 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
| @@ -1048,20 +1048,15 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 1048 | return err; | 1048 | return err; |
| 1049 | } | 1049 | } |
| 1050 | 1050 | ||
| 1051 | static int tun_get_iff(struct net *net, struct file *file, struct ifreq *ifr) | 1051 | static int tun_get_iff(struct net *net, struct tun_struct *tun, |
| 1052 | struct ifreq *ifr) | ||
| 1052 | { | 1053 | { |
| 1053 | struct tun_struct *tun = tun_get(file); | ||
| 1054 | |||
| 1055 | if (!tun) | ||
| 1056 | return -EBADFD; | ||
| 1057 | |||
| 1058 | DBG(KERN_INFO "%s: tun_get_iff\n", tun->dev->name); | 1054 | DBG(KERN_INFO "%s: tun_get_iff\n", tun->dev->name); |
| 1059 | 1055 | ||
| 1060 | strcpy(ifr->ifr_name, tun->dev->name); | 1056 | strcpy(ifr->ifr_name, tun->dev->name); |
| 1061 | 1057 | ||
| 1062 | ifr->ifr_flags = tun_flags(tun); | 1058 | ifr->ifr_flags = tun_flags(tun); |
| 1063 | 1059 | ||
| 1064 | tun_put(tun); | ||
| 1065 | return 0; | 1060 | return 0; |
| 1066 | } | 1061 | } |
| 1067 | 1062 | ||
| @@ -1105,8 +1100,8 @@ static int set_offload(struct net_device *dev, unsigned long arg) | |||
| 1105 | return 0; | 1100 | return 0; |
| 1106 | } | 1101 | } |
| 1107 | 1102 | ||
| 1108 | static int tun_chr_ioctl(struct inode *inode, struct file *file, | 1103 | static long tun_chr_ioctl(struct file *file, unsigned int cmd, |
| 1109 | unsigned int cmd, unsigned long arg) | 1104 | unsigned long arg) |
| 1110 | { | 1105 | { |
| 1111 | struct tun_file *tfile = file->private_data; | 1106 | struct tun_file *tfile = file->private_data; |
| 1112 | struct tun_struct *tun; | 1107 | struct tun_struct *tun; |
| @@ -1128,34 +1123,32 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
| 1128 | (unsigned int __user*)argp); | 1123 | (unsigned int __user*)argp); |
| 1129 | } | 1124 | } |
| 1130 | 1125 | ||
| 1126 | rtnl_lock(); | ||
| 1127 | |||
| 1131 | tun = __tun_get(tfile); | 1128 | tun = __tun_get(tfile); |
| 1132 | if (cmd == TUNSETIFF && !tun) { | 1129 | if (cmd == TUNSETIFF && !tun) { |
| 1133 | int err; | ||
| 1134 | |||
| 1135 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; | 1130 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; |
| 1136 | 1131 | ||
| 1137 | rtnl_lock(); | 1132 | ret = tun_set_iff(tfile->net, file, &ifr); |
| 1138 | err = tun_set_iff(tfile->net, file, &ifr); | ||
| 1139 | rtnl_unlock(); | ||
| 1140 | 1133 | ||
| 1141 | if (err) | 1134 | if (ret) |
| 1142 | return err; | 1135 | goto unlock; |
| 1143 | 1136 | ||
| 1144 | if (copy_to_user(argp, &ifr, sizeof(ifr))) | 1137 | if (copy_to_user(argp, &ifr, sizeof(ifr))) |
| 1145 | return -EFAULT; | 1138 | ret = -EFAULT; |
| 1146 | return 0; | 1139 | goto unlock; |
| 1147 | } | 1140 | } |
| 1148 | 1141 | ||
| 1149 | 1142 | ret = -EBADFD; | |
| 1150 | if (!tun) | 1143 | if (!tun) |
| 1151 | return -EBADFD; | 1144 | goto unlock; |
| 1152 | 1145 | ||
| 1153 | DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd); | 1146 | DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd); |
| 1154 | 1147 | ||
| 1155 | ret = 0; | 1148 | ret = 0; |
| 1156 | switch (cmd) { | 1149 | switch (cmd) { |
| 1157 | case TUNGETIFF: | 1150 | case TUNGETIFF: |
| 1158 | ret = tun_get_iff(current->nsproxy->net_ns, file, &ifr); | 1151 | ret = tun_get_iff(current->nsproxy->net_ns, tun, &ifr); |
| 1159 | if (ret) | 1152 | if (ret) |
| 1160 | break; | 1153 | break; |
| 1161 | 1154 | ||
| @@ -1201,7 +1194,6 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
| 1201 | 1194 | ||
| 1202 | case TUNSETLINK: | 1195 | case TUNSETLINK: |
| 1203 | /* Only allow setting the type when the interface is down */ | 1196 | /* Only allow setting the type when the interface is down */ |
| 1204 | rtnl_lock(); | ||
| 1205 | if (tun->dev->flags & IFF_UP) { | 1197 | if (tun->dev->flags & IFF_UP) { |
| 1206 | DBG(KERN_INFO "%s: Linktype set failed because interface is up\n", | 1198 | DBG(KERN_INFO "%s: Linktype set failed because interface is up\n", |
| 1207 | tun->dev->name); | 1199 | tun->dev->name); |
| @@ -1211,7 +1203,6 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
| 1211 | DBG(KERN_INFO "%s: linktype set to %d\n", tun->dev->name, tun->dev->type); | 1203 | DBG(KERN_INFO "%s: linktype set to %d\n", tun->dev->name, tun->dev->type); |
| 1212 | ret = 0; | 1204 | ret = 0; |
| 1213 | } | 1205 | } |
| 1214 | rtnl_unlock(); | ||
| 1215 | break; | 1206 | break; |
| 1216 | 1207 | ||
| 1217 | #ifdef TUN_DEBUG | 1208 | #ifdef TUN_DEBUG |
| @@ -1220,9 +1211,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
| 1220 | break; | 1211 | break; |
| 1221 | #endif | 1212 | #endif |
| 1222 | case TUNSETOFFLOAD: | 1213 | case TUNSETOFFLOAD: |
| 1223 | rtnl_lock(); | ||
| 1224 | ret = set_offload(tun->dev, arg); | 1214 | ret = set_offload(tun->dev, arg); |
| 1225 | rtnl_unlock(); | ||
| 1226 | break; | 1215 | break; |
| 1227 | 1216 | ||
| 1228 | case TUNSETTXFILTER: | 1217 | case TUNSETTXFILTER: |
| @@ -1230,9 +1219,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
| 1230 | ret = -EINVAL; | 1219 | ret = -EINVAL; |
| 1231 | if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) | 1220 | if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV) |
| 1232 | break; | 1221 | break; |
| 1233 | rtnl_lock(); | ||
| 1234 | ret = update_filter(&tun->txflt, (void __user *)arg); | 1222 | ret = update_filter(&tun->txflt, (void __user *)arg); |
| 1235 | rtnl_unlock(); | ||
| 1236 | break; | 1223 | break; |
| 1237 | 1224 | ||
| 1238 | case SIOCGIFHWADDR: | 1225 | case SIOCGIFHWADDR: |
| @@ -1248,9 +1235,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
| 1248 | DBG(KERN_DEBUG "%s: set hw address: %pM\n", | 1235 | DBG(KERN_DEBUG "%s: set hw address: %pM\n", |
| 1249 | tun->dev->name, ifr.ifr_hwaddr.sa_data); | 1236 | tun->dev->name, ifr.ifr_hwaddr.sa_data); |
| 1250 | 1237 | ||
| 1251 | rtnl_lock(); | ||
| 1252 | ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); | 1238 | ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); |
| 1253 | rtnl_unlock(); | ||
| 1254 | break; | 1239 | break; |
| 1255 | 1240 | ||
| 1256 | case TUNGETSNDBUF: | 1241 | case TUNGETSNDBUF: |
| @@ -1273,7 +1258,10 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, | |||
| 1273 | break; | 1258 | break; |
| 1274 | }; | 1259 | }; |
| 1275 | 1260 | ||
| 1276 | tun_put(tun); | 1261 | unlock: |
| 1262 | rtnl_unlock(); | ||
| 1263 | if (tun) | ||
| 1264 | tun_put(tun); | ||
| 1277 | return ret; | 1265 | return ret; |
| 1278 | } | 1266 | } |
| 1279 | 1267 | ||
| @@ -1361,7 +1349,7 @@ static const struct file_operations tun_fops = { | |||
| 1361 | .write = do_sync_write, | 1349 | .write = do_sync_write, |
| 1362 | .aio_write = tun_chr_aio_write, | 1350 | .aio_write = tun_chr_aio_write, |
| 1363 | .poll = tun_chr_poll, | 1351 | .poll = tun_chr_poll, |
| 1364 | .ioctl = tun_chr_ioctl, | 1352 | .unlocked_ioctl = tun_chr_ioctl, |
| 1365 | .open = tun_chr_open, | 1353 | .open = tun_chr_open, |
| 1366 | .release = tun_chr_close, | 1354 | .release = tun_chr_close, |
| 1367 | .fasync = tun_chr_fasync | 1355 | .fasync = tun_chr_fasync |
