Main Page | Class List | File List | Class Members | File Members

ip_sockglue.c

Go to the documentation of this file.
00001 /* 00002 * INET An implementation of the TCP/IP protocol suite for the LINUX 00003 * operating system. INET is implemented using the BSD Socket 00004 * interface as the means of communication with the user level. 00005 * 00006 * The IP to API glue. 00007 * 00008 * Version: $Id: ip_sockglue.c,v 1.61 2001/10/20 00:00:11 davem Exp $ 00009 * 00010 * Authors: see ip.c 00011 * 00012 * Fixes: 00013 * Many : Split from ip.c , see ip.c for history. 00014 * Martin Mares : TOS setting fixed. 00015 * Alan Cox : Fixed a couple of oopses in Martin's 00016 * TOS tweaks. 00017 * Mike McLagan : Routing by source 00018 */ 00019 00020 #include <linux/config.h> 00021 #include <linux/types.h> 00022 #include <linux/mm.h> 00023 #include <linux/sched.h> 00024 #include <linux/skbuff.h> 00025 #include <linux/ip.h> 00026 #include <linux/icmp.h> 00027 #include <linux/netdevice.h> 00028 #include <net/sock.h> 00029 #include <net/ip.h> 00030 #include <net/icmp.h> 00031 #include <net/tcp.h> 00032 #include <linux/tcp.h> 00033 #include <linux/udp.h> 00034 #include <linux/igmp.h> 00035 #include <linux/netfilter.h> 00036 #include <linux/route.h> 00037 #include <linux/mroute.h> 00038 #include <net/route.h> 00039 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 00040 #include <net/transp_v6.h> 00041 #endif 00042 00043 #include <linux/errqueue.h> 00044 #include <asm/uaccess.h> 00045 00046 #define IP_CMSG_PKTINFO 1 00047 #define IP_CMSG_TTL 2 00048 #define IP_CMSG_TOS 4 00049 #define IP_CMSG_RECVOPTS 8 00050 #define IP_CMSG_RETOPTS 16 00051 00052 /* 00053 * SOL_IP control messages. 00054 */ 00055 00056 static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) 00057 { 00058 struct in_pktinfo info; 00059 struct rtable *rt = (struct rtable *)skb->dst; 00060 00061 info.ipi_addr.s_addr = skb->nh.iph->daddr; 00062 if (rt) { 00063 info.ipi_ifindex = rt->rt_iif; 00064 info.ipi_spec_dst.s_addr = rt->rt_spec_dst; 00065 } else { 00066 info.ipi_ifindex = 0; 00067 info.ipi_spec_dst.s_addr = 0; 00068 } 00069 00070 put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info); 00071 } 00072 00073 static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb) 00074 { 00075 int ttl = skb->nh.iph->ttl; 00076 put_cmsg(msg, SOL_IP, IP_TTL, sizeof(int), &ttl); 00077 } 00078 00079 static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb) 00080 { 00081 put_cmsg(msg, SOL_IP, IP_TOS, 1, &skb->nh.iph->tos); 00082 } 00083 00084 static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb) 00085 { 00086 if (IPCB(skb)->opt.optlen == 0) 00087 return; 00088 00089 put_cmsg(msg, SOL_IP, IP_RECVOPTS, IPCB(skb)->opt.optlen, skb->nh.iph+1); 00090 } 00091 00092 00093 void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) 00094 { 00095 unsigned char optbuf[sizeof(struct ip_options) + 40]; 00096 struct ip_options * opt = (struct ip_options*)optbuf; 00097 00098 if (IPCB(skb)->opt.optlen == 0) 00099 return; 00100 00101 if (ip_options_echo(opt, skb)) { 00102 msg->msg_flags |= MSG_CTRUNC; 00103 return; 00104 } 00105 ip_options_undo(opt); 00106 00107 put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data); 00108 } 00109 00110 00111 void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) 00112 { 00113 unsigned flags = skb->sk->protinfo.af_inet.cmsg_flags; 00114 00115 /* Ordered by supposed usage frequency */ 00116 if (flags & 1) 00117 ip_cmsg_recv_pktinfo(msg, skb); 00118 if ((flags>>=1) == 0) 00119 return; 00120 00121 if (flags & 1) 00122 ip_cmsg_recv_ttl(msg, skb); 00123 if ((flags>>=1) == 0) 00124 return; 00125 00126 if (flags & 1) 00127 ip_cmsg_recv_tos(msg, skb); 00128 if ((flags>>=1) == 0) 00129 return; 00130 00131 if (flags & 1) 00132 ip_cmsg_recv_opts(msg, skb); 00133 if ((flags>>=1) == 0) 00134 return; 00135 00136 if (flags & 1) 00137 ip_cmsg_recv_retopts(msg, skb); 00138 } 00139 00140 int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) 00141 { 00142 int err; 00143 struct cmsghdr *cmsg; 00144 00145 for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { 00146 if (cmsg->cmsg_len < sizeof(struct cmsghdr) || 00147 (unsigned long)(((char*)cmsg - (char*)msg->msg_control) 00148 + cmsg->cmsg_len) > msg->msg_controllen) { 00149 return -EINVAL; 00150 } 00151 if (cmsg->cmsg_level != SOL_IP) 00152 continue; 00153 switch (cmsg->cmsg_type) { 00154 case IP_RETOPTS: 00155 err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); 00156 err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40, 0); 00157 if (err) 00158 return err; 00159 break; 00160 case IP_PKTINFO: 00161 { 00162 struct in_pktinfo *info; 00163 if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo))) 00164 return -EINVAL; 00165 info = (struct in_pktinfo *)CMSG_DATA(cmsg); 00166 ipc->oif = info->ipi_ifindex; 00167 ipc->addr = info->ipi_spec_dst.s_addr; 00168 break; 00169 } 00170 default: 00171 return -EINVAL; 00172 } 00173 } 00174 return 0; 00175 } 00176 00177 00178 /* Special input handler for packets catched by router alert option. 00179 They are selected only by protocol field, and then processed likely 00180 local ones; but only if someone wants them! Otherwise, router 00181 not running rsvpd will kill RSVP. 00182 00183 It is user level problem, what it will make with them. 00184 I have no idea, how it will masquearde or NAT them (it is joke, joke :-)), 00185 but receiver should be enough clever f.e. to forward mtrace requests, 00186 sent to multicast group to reach destination designated router. 00187 */ 00188 struct ip_ra_chain *ip_ra_chain; 00189 rwlock_t ip_ra_lock = RW_LOCK_UNLOCKED; 00190 00191 int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)) 00192 { 00193 struct ip_ra_chain *ra, *new_ra, **rap; 00194 00195 if (sk->type != SOCK_RAW || sk->num == IPPROTO_RAW) 00196 return -EINVAL; 00197 00198 new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; 00199 00200 write_lock_bh(&ip_ra_lock); 00201 for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) { 00202 if (ra->sk == sk) { 00203 if (on) { 00204 write_unlock_bh(&ip_ra_lock); 00205 if (new_ra) 00206 kfree(new_ra); 00207 return -EADDRINUSE; 00208 } 00209 *rap = ra->next; 00210 write_unlock_bh(&ip_ra_lock); 00211 00212 if (ra->destructor) 00213 ra->destructor(sk); 00214 sock_put(sk); 00215 kfree(ra); 00216 return 0; 00217 } 00218 } 00219 if (new_ra == NULL) { 00220 write_unlock_bh(&ip_ra_lock); 00221 return -ENOBUFS; 00222 } 00223 new_ra->sk = sk; 00224 new_ra->destructor = destructor; 00225 00226 new_ra->next = ra; 00227 *rap = new_ra; 00228 sock_hold(sk); 00229 write_unlock_bh(&ip_ra_lock); 00230 00231 return 0; 00232 } 00233 00234 void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 00235 u16 port, u32 info, u8 *payload) 00236 { 00237 struct sock_exterr_skb *serr; 00238 00239 if (!sk->protinfo.af_inet.recverr) 00240 return; 00241 00242 skb = skb_clone(skb, GFP_ATOMIC); 00243 if (!skb) 00244 return; 00245 00246 serr = SKB_EXT_ERR(skb); 00247 serr->ee.ee_errno = err; 00248 serr->ee.ee_origin = SO_EE_ORIGIN_ICMP; 00249 serr->ee.ee_type = skb->h.icmph->type; 00250 serr->ee.ee_code = skb->h.icmph->code; 00251 serr->ee.ee_pad = 0; 00252 serr->ee.ee_info = info; 00253 serr->ee.ee_data = 0; 00254 serr->addr_offset = (u8*)&(((struct iphdr*)(skb->h.icmph+1))->daddr) - skb->nh.raw; 00255 serr->port = port; 00256 00257 skb->h.raw = payload; 00258 if (!skb_pull(skb, payload - skb->data) || 00259 sock_queue_err_skb(sk, skb)) 00260 kfree_skb(skb); 00261 } 00262 00263 void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info) 00264 { 00265 struct sock_exterr_skb *serr; 00266 struct iphdr *iph; 00267 struct sk_buff *skb; 00268 00269 if (!sk->protinfo.af_inet.recverr) 00270 return; 00271 00272 skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC); 00273 if (!skb) 00274 return; 00275 00276 iph = (struct iphdr*)skb_put(skb, sizeof(struct iphdr)); 00277 skb->nh.iph = iph; 00278 iph->daddr = daddr; 00279 00280 serr = SKB_EXT_ERR(skb); 00281 serr->ee.ee_errno = err; 00282 serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL; 00283 serr->ee.ee_type = 0; 00284 serr->ee.ee_code = 0; 00285 serr->ee.ee_pad = 0; 00286 serr->ee.ee_info = info; 00287 serr->ee.ee_data = 0; 00288 serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw; 00289 serr->port = port; 00290 00291 skb->h.raw = skb->tail; 00292 __skb_pull(skb, skb->tail - skb->data); 00293 00294 if (sock_queue_err_skb(sk, skb)) 00295 kfree_skb(skb); 00296 } 00297 00298 /* 00299 * Handle MSG_ERRQUEUE 00300 */ 00301 int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) 00302 { 00303 struct sock_exterr_skb *serr; 00304 struct sk_buff *skb, *skb2; 00305 struct sockaddr_in *sin; 00306 struct { 00307 struct sock_extended_err ee; 00308 struct sockaddr_in offender; 00309 } errhdr; 00310 int err; 00311 int copied; 00312 00313 err = -EAGAIN; 00314 skb = skb_dequeue(&sk->error_queue); 00315 if (skb == NULL) 00316 goto out; 00317 00318 copied = skb->len; 00319 if (copied > len) { 00320 msg->msg_flags |= MSG_TRUNC; 00321 copied = len; 00322 } 00323 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 00324 if (err) 00325 goto out_free_skb; 00326 00327 sock_recv_timestamp(msg, sk, skb); 00328 00329 serr = SKB_EXT_ERR(skb); 00330 00331 sin = (struct sockaddr_in *)msg->msg_name; 00332 if (sin) { 00333 sin->sin_family = AF_INET; 00334 sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset); 00335 sin->sin_port = serr->port; 00336 memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); 00337 } 00338 00339 memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); 00340 sin = &errhdr.offender; 00341 sin->sin_family = AF_UNSPEC; 00342 if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) { 00343 sin->sin_family = AF_INET; 00344 sin->sin_addr.s_addr = skb->nh.iph->saddr; 00345 sin->sin_port = 0; 00346 memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); 00347 if (sk->protinfo.af_inet.cmsg_flags) 00348 ip_cmsg_recv(msg, skb); 00349 } 00350 00351 put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr); 00352 00353 /* Now we could try to dump offended packet options */ 00354 00355 msg->msg_flags |= MSG_ERRQUEUE; 00356 err = copied; 00357 00358 /* Reset and regenerate socket error */ 00359 spin_lock_irq(&sk->error_queue.lock); 00360 sk->err = 0; 00361 if ((skb2 = skb_peek(&sk->error_queue)) != NULL) { 00362 sk->err = SKB_EXT_ERR(skb2)->ee.ee_errno; 00363 spin_unlock_irq(&sk->error_queue.lock); 00364 sk->error_report(sk); 00365 } else { 00366 spin_unlock_irq(&sk->error_queue.lock); 00367 } 00368 00369 out_free_skb: 00370 kfree_skb(skb); 00371 out: 00372 return err; 00373 } 00374 00375 00376 /* 00377 * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on 00378 * an IP socket. 00379 */ 00380 00381 int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) 00382 { 00383 int val=0,err; 00384 00385 if (level != SOL_IP) 00386 return -ENOPROTOOPT; 00387 00388 if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | 00389 (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | 00390 (1<<IP_RETOPTS) | (1<<IP_TOS) | 00391 (1<<IP_TTL) | (1<<IP_HDRINCL) | 00392 (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 00393 (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || 00394 optname == IP_MULTICAST_TTL || 00395 optname == IP_MULTICAST_LOOP) { 00396 if (optlen >= sizeof(int)) { 00397 if (get_user(val, (int *) optval)) 00398 return -EFAULT; 00399 } else if (optlen >= sizeof(char)) { 00400 unsigned char ucval; 00401 00402 if (get_user(ucval, (unsigned char *) optval)) 00403 return -EFAULT; 00404 val = (int) ucval; 00405 } 00406 } 00407 00408 /* If optlen==0, it is equivalent to val == 0 */ 00409 00410 #ifdef CONFIG_IP_MROUTE 00411 if (optname >= MRT_BASE && optname <= (MRT_BASE + 10)) 00412 return ip_mroute_setsockopt(sk,optname,optval,optlen); 00413 #endif 00414 00415 err = 0; 00416 lock_sock(sk); 00417 00418 switch (optname) { 00419 case IP_OPTIONS: 00420 { 00421 struct ip_options * opt = NULL; 00422 if (optlen > 40 || optlen < 0) 00423 goto e_inval; 00424 err = ip_options_get(&opt, optval, optlen, 1); 00425 if (err) 00426 break; 00427 if (sk->type == SOCK_STREAM) { 00428 struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; 00429 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 00430 if (sk->family == PF_INET || 00431 (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE)) 00432 && sk->daddr != LOOPBACK4_IPV6)) { 00433 #endif 00434 if (opt) 00435 tp->ext_header_len = opt->optlen; 00436 tcp_sync_mss(sk, tp->pmtu_cookie); 00437 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 00438 } 00439 #endif 00440 } 00441 opt = xchg(&sk->protinfo.af_inet.opt, opt); 00442 if (opt) 00443 kfree(opt); 00444 break; 00445 } 00446 case IP_PKTINFO: 00447 if (val) 00448 sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_PKTINFO; 00449 else 00450 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_PKTINFO; 00451 break; 00452 case IP_RECVTTL: 00453 if (val) 00454 sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_TTL; 00455 else 00456 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TTL; 00457 break; 00458 case IP_RECVTOS: 00459 if (val) 00460 sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_TOS; 00461 else 00462 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TOS; 00463 break; 00464 case IP_RECVOPTS: 00465 if (val) 00466 sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_RECVOPTS; 00467 else 00468 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RECVOPTS; 00469 break; 00470 case IP_RETOPTS: 00471 if (val) 00472 sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_RETOPTS; 00473 else 00474 sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RETOPTS; 00475 break; 00476 case IP_TOS: /* This sets both TOS and Precedence */ 00477 if (sk->type == SOCK_STREAM) { 00478 val &= ~3; 00479 val |= sk->protinfo.af_inet.tos & 3; 00480 } 00481 if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && 00482 !capable(CAP_NET_ADMIN)) { 00483 err = -EPERM; 00484 break; 00485 } 00486 if (sk->protinfo.af_inet.tos != val) { 00487 sk->protinfo.af_inet.tos=val; 00488 sk->priority = rt_tos2priority(val); 00489 sk_dst_reset(sk); 00490 } 00491 break; 00492 case IP_TTL: 00493 if (optlen<1) 00494 goto e_inval; 00495 if(val==-1) 00496 val = sysctl_ip_default_ttl; 00497 if(val<1||val>255) 00498 goto e_inval; 00499 sk->protinfo.af_inet.ttl=val; 00500 break; 00501 case IP_HDRINCL: 00502 if(sk->type!=SOCK_RAW) { 00503 err = -ENOPROTOOPT; 00504 break; 00505 } 00506 sk->protinfo.af_inet.hdrincl=val?1:0; 00507 break; 00508 case IP_MTU_DISCOVER: 00509 if (val<0 || val>2) 00510 goto e_inval; 00511 sk->protinfo.af_inet.pmtudisc = val; 00512 break; 00513 case IP_RECVERR: 00514 sk->protinfo.af_inet.recverr = !!val; 00515 if (!val) 00516 skb_queue_purge(&sk->error_queue); 00517 break; 00518 case IP_MULTICAST_TTL: 00519 if (sk->type == SOCK_STREAM) 00520 goto e_inval; 00521 if (optlen<1) 00522 goto e_inval; 00523 if (val==-1) 00524 val = 1; 00525 if (val < 0 || val > 255) 00526 goto e_inval; 00527 sk->protinfo.af_inet.mc_ttl=val; 00528 break; 00529 case IP_MULTICAST_LOOP: 00530 if (optlen<1) 00531 goto e_inval; 00532 sk->protinfo.af_inet.mc_loop = val ? 1 : 0; 00533 break; 00534 case IP_MULTICAST_IF: 00535 { 00536 struct ip_mreqn mreq; 00537 struct net_device *dev = NULL; 00538 00539 if (sk->type == SOCK_STREAM) 00540 goto e_inval; 00541 /* 00542 * Check the arguments are allowable 00543 */ 00544 00545 err = -EFAULT; 00546 if (optlen >= sizeof(struct ip_mreqn)) { 00547 if (copy_from_user(&mreq,optval,sizeof(mreq))) 00548 break; 00549 } else { 00550 memset(&mreq, 0, sizeof(mreq)); 00551 if (optlen >= sizeof(struct in_addr) && 00552 copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr))) 00553 break; 00554 } 00555 00556 if (!mreq.imr_ifindex) { 00557 if (mreq.imr_address.s_addr == INADDR_ANY) { 00558 sk->protinfo.af_inet.mc_index = 0; 00559 sk->protinfo.af_inet.mc_addr = 0; 00560 err = 0; 00561 break; 00562 } 00563 dev = ip_dev_find(mreq.imr_address.s_addr); 00564 if (dev) { 00565 mreq.imr_ifindex = dev->ifindex; 00566 dev_put(dev); 00567 } 00568 } else 00569 dev = __dev_get_by_index(mreq.imr_ifindex); 00570 00571 00572 err = -EADDRNOTAVAIL; 00573 if (!dev) 00574 break; 00575 00576 err = -EINVAL; 00577 if (sk->bound_dev_if && mreq.imr_ifindex != sk->bound_dev_if) 00578 break; 00579 00580 sk->protinfo.af_inet.mc_index = mreq.imr_ifindex; 00581 sk->protinfo.af_inet.mc_addr = mreq.imr_address.s_addr; 00582 err = 0; 00583 break; 00584 } 00585 00586 case IP_ADD_MEMBERSHIP: 00587 case IP_DROP_MEMBERSHIP: 00588 { 00589 struct ip_mreqn mreq; 00590 00591 if (optlen < sizeof(struct ip_mreq)) 00592 goto e_inval; 00593 err = -EFAULT; 00594 if (optlen >= sizeof(struct ip_mreqn)) { 00595 if(copy_from_user(&mreq,optval,sizeof(mreq))) 00596 break; 00597 } else { 00598 memset(&mreq, 0, sizeof(mreq)); 00599 if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq))) 00600 break; 00601 } 00602 00603 if (optname == IP_ADD_MEMBERSHIP) 00604 err = ip_mc_join_group(sk, &mreq); 00605 else 00606 err = ip_mc_leave_group(sk, &mreq); 00607 break; 00608 } 00609 case IP_MSFILTER: 00610 { 00611 struct ip_msfilter *msf; 00612 00613 if (optlen < IP_MSFILTER_SIZE(0)) 00614 goto e_inval; 00615 msf = (struct ip_msfilter *)kmalloc(optlen, GFP_KERNEL); 00616 if (msf == 0) { 00617 err = -ENOBUFS; 00618 break; 00619 } 00620 err = -EFAULT; 00621 if (copy_from_user(msf, optval, optlen)) { 00622 kfree(msf); 00623 break; 00624 } 00625 err = ip_mc_msfilter(sk, msf, 0); 00626 kfree(msf); 00627 break; 00628 } 00629 case IP_BLOCK_SOURCE: 00630 case IP_UNBLOCK_SOURCE: 00631 case IP_ADD_SOURCE_MEMBERSHIP: 00632 case IP_DROP_SOURCE_MEMBERSHIP: 00633 { 00634 struct ip_mreq_source mreqs; 00635 int omode, add; 00636 00637 if (optlen != sizeof(struct ip_mreq_source)) 00638 goto e_inval; 00639 if (copy_from_user(&mreqs, optval, sizeof(mreqs))) { 00640 err = -EFAULT; 00641 break; 00642 } 00643 if (optname == IP_BLOCK_SOURCE) { 00644 omode = MCAST_EXCLUDE; 00645 add = 1; 00646 } else if (optname == IP_UNBLOCK_SOURCE) { 00647 omode = MCAST_EXCLUDE; 00648 add = 0; 00649 } else if (optname == IP_ADD_SOURCE_MEMBERSHIP) { 00650 struct ip_mreqn mreq; 00651 00652 mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr; 00653 mreq.imr_address.s_addr = mreqs.imr_interface; 00654 mreq.imr_ifindex = 0; 00655 err = ip_mc_join_group(sk, &mreq); 00656 if (err) 00657 break; 00658 omode = MCAST_INCLUDE; 00659 add = 1; 00660 } else /*IP_DROP_SOURCE_MEMBERSHIP */ { 00661 omode = MCAST_INCLUDE; 00662 add = 0; 00663 } 00664 err = ip_mc_source(add, omode, sk, &mreqs, 0); 00665 break; 00666 } 00667 case MCAST_JOIN_GROUP: 00668 case MCAST_LEAVE_GROUP: 00669 { 00670 struct group_req greq; 00671 struct sockaddr_in *psin; 00672 struct ip_mreqn mreq; 00673 00674 if (optlen < sizeof(struct group_req)) 00675 goto e_inval; 00676 err = -EFAULT; 00677 if(copy_from_user(&greq, optval, sizeof(greq))) 00678 break; 00679 psin = (struct sockaddr_in *)&greq.gr_group; 00680 if (psin->sin_family != AF_INET) 00681 goto e_inval; 00682 memset(&mreq, 0, sizeof(mreq)); 00683 mreq.imr_multiaddr = psin->sin_addr; 00684 mreq.imr_ifindex = greq.gr_interface; 00685 00686 if (optname == MCAST_JOIN_GROUP) 00687 err = ip_mc_join_group(sk, &mreq); 00688 else 00689 err = ip_mc_leave_group(sk, &mreq); 00690 break; 00691 } 00692 case MCAST_JOIN_SOURCE_GROUP: 00693 case MCAST_LEAVE_SOURCE_GROUP: 00694 case MCAST_BLOCK_SOURCE: 00695 case MCAST_UNBLOCK_SOURCE: 00696 { 00697 struct group_source_req greqs; 00698 struct ip_mreq_source mreqs; 00699 struct sockaddr_in *psin; 00700 int omode, add; 00701 00702 if (optlen != sizeof(struct group_source_req)) 00703 goto e_inval; 00704 if (copy_from_user(&greqs, optval, sizeof(greqs))) { 00705 err = -EFAULT; 00706 break; 00707 } 00708 if (greqs.gsr_group.ss_family != AF_INET || 00709 greqs.gsr_source.ss_family != AF_INET) { 00710 err = -EADDRNOTAVAIL; 00711 break; 00712 } 00713 psin = (struct sockaddr_in *)&greqs.gsr_group; 00714 mreqs.imr_multiaddr = psin->sin_addr.s_addr; 00715 psin = (struct sockaddr_in *)&greqs.gsr_source; 00716 mreqs.imr_sourceaddr = psin->sin_addr.s_addr; 00717 mreqs.imr_interface = 0; /* use index for mc_source */ 00718 00719 if (optname == MCAST_BLOCK_SOURCE) { 00720 omode = MCAST_EXCLUDE; 00721 add = 1; 00722 } else if (optname == MCAST_UNBLOCK_SOURCE) { 00723 omode = MCAST_EXCLUDE; 00724 add = 0; 00725 } else if (optname == MCAST_JOIN_SOURCE_GROUP) { 00726 struct ip_mreqn mreq; 00727 00728 psin = (struct sockaddr_in *)&greqs.gsr_group; 00729 mreq.imr_multiaddr = psin->sin_addr; 00730 mreq.imr_address.s_addr = 0; 00731 mreq.imr_ifindex = greqs.gsr_interface; 00732 err = ip_mc_join_group(sk, &mreq); 00733 if (err) 00734 break; 00735 omode = MCAST_INCLUDE; 00736 add = 1; 00737 } else /* MCAST_LEAVE_SOURCE_GROUP */ { 00738 omode = MCAST_INCLUDE; 00739 add = 0; 00740 } 00741 err = ip_mc_source(add, omode, sk, &mreqs, 00742 greqs.gsr_interface); 00743 break; 00744 } 00745 case MCAST_MSFILTER: 00746 { 00747 struct sockaddr_in *psin; 00748 struct ip_msfilter *msf = 0; 00749 struct group_filter *gsf = 0; 00750 int msize, i, ifindex; 00751 00752 if (optlen < GROUP_FILTER_SIZE(0)) 00753 goto e_inval; 00754 gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL); 00755 if (gsf == 0) { 00756 err = -ENOBUFS; 00757 break; 00758 } 00759 err = -EFAULT; 00760 if (copy_from_user(gsf, optval, optlen)) { 00761 goto mc_msf_out; 00762 } 00763 if (GROUP_FILTER_SIZE(gsf->gf_numsrc) < optlen) { 00764 err = EINVAL; 00765 goto mc_msf_out; 00766 } 00767 msize = IP_MSFILTER_SIZE(gsf->gf_numsrc); 00768 msf = (struct ip_msfilter *)kmalloc(msize,GFP_KERNEL); 00769 if (msf == 0) { 00770 err = -ENOBUFS; 00771 goto mc_msf_out; 00772 } 00773 ifindex = gsf->gf_interface; 00774 psin = (struct sockaddr_in *)&gsf->gf_group; 00775 if (psin->sin_family != AF_INET) { 00776 err = -EADDRNOTAVAIL; 00777 goto mc_msf_out; 00778 } 00779 msf->imsf_multiaddr = psin->sin_addr.s_addr; 00780 msf->imsf_interface = 0; 00781 msf->imsf_fmode = gsf->gf_fmode; 00782 msf->imsf_numsrc = gsf->gf_numsrc; 00783 err = -EADDRNOTAVAIL; 00784 for (i=0; i<gsf->gf_numsrc; ++i) { 00785 psin = (struct sockaddr_in *)&gsf->gf_slist[i]; 00786 00787 if (psin->sin_family != AF_INET) 00788 goto mc_msf_out; 00789 msf->imsf_slist[i] = psin->sin_addr.s_addr; 00790 } 00791 kfree(gsf); 00792 gsf = 0; 00793 00794 err = ip_mc_msfilter(sk, msf, ifindex); 00795 mc_msf_out: 00796 if (msf) 00797 kfree(msf); 00798 if (gsf) 00799 kfree(gsf); 00800 break; 00801 } 00802 case IP_ROUTER_ALERT: 00803 err = ip_ra_control(sk, val ? 1 : 0, NULL); 00804 break; 00805 00806 case IP_FREEBIND: 00807 if (optlen<1) 00808 goto e_inval; 00809 sk->protinfo.af_inet.freebind = !!val; 00810 break; 00811 00812 default: 00813 #ifdef CONFIG_NETFILTER 00814 err = nf_setsockopt(sk, PF_INET, optname, optval, 00815 optlen); 00816 #else 00817 err = -ENOPROTOOPT; 00818 #endif 00819 break; 00820 } 00821 release_sock(sk); 00822 return err; 00823 00824 e_inval: 00825 release_sock(sk); 00826 return -EINVAL; 00827 } 00828 00829 /* 00830 * Get the options. Note for future reference. The GET of IP options gets the 00831 * _received_ ones. The set sets the _sent_ ones. 00832 */ 00833 00834 int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) 00835 { 00836 int val; 00837 int len; 00838 00839 if(level!=SOL_IP) 00840 return -EOPNOTSUPP; 00841 00842 #ifdef CONFIG_IP_MROUTE 00843 if(optname>=MRT_BASE && optname <=MRT_BASE+10) 00844 { 00845 return ip_mroute_getsockopt(sk,optname,optval,optlen); 00846 } 00847 #endif 00848 00849 if(get_user(len,optlen)) 00850 return -EFAULT; 00851 if(len < 0) 00852 return -EINVAL; 00853 00854 lock_sock(sk); 00855 00856 switch(optname) { 00857 case IP_OPTIONS: 00858 { 00859 unsigned char optbuf[sizeof(struct ip_options)+40]; 00860 struct ip_options * opt = (struct ip_options*)optbuf; 00861 opt->optlen = 0; 00862 if (sk->protinfo.af_inet.opt) 00863 memcpy(optbuf, sk->protinfo.af_inet.opt, 00864 sizeof(struct ip_options)+ 00865 sk->protinfo.af_inet.opt->optlen); 00866 release_sock(sk); 00867 00868 if (opt->optlen == 0) 00869 return put_user(0, optlen); 00870 00871 ip_options_undo(opt); 00872 00873 len = min_t(unsigned int, len, opt->optlen); 00874 if(put_user(len, optlen)) 00875 return -EFAULT; 00876 if(copy_to_user(optval, opt->__data, len)) 00877 return -EFAULT; 00878 return 0; 00879 } 00880 case IP_PKTINFO: 00881 val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_PKTINFO) != 0; 00882 break; 00883 case IP_RECVTTL: 00884 val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TTL) != 0; 00885 break; 00886 case IP_RECVTOS: 00887 val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TOS) != 0; 00888 break; 00889 case IP_RECVOPTS: 00890 val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RECVOPTS) != 0; 00891 break; 00892 case IP_RETOPTS: 00893 val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RETOPTS) != 0; 00894 break; 00895 case IP_TOS: 00896 val=sk->protinfo.af_inet.tos; 00897 break; 00898 case IP_TTL: 00899 val=sk->protinfo.af_inet.ttl; 00900 break; 00901 case IP_HDRINCL: 00902 val=sk->protinfo.af_inet.hdrincl; 00903 break; 00904 case IP_MTU_DISCOVER: 00905 val=sk->protinfo.af_inet.pmtudisc; 00906 break; 00907 case IP_MTU: 00908 { 00909 struct dst_entry *dst; 00910 val = 0; 00911 dst = sk_dst_get(sk); 00912 if (dst) { 00913 val = dst->pmtu; 00914 dst_release(dst); 00915 } 00916 if (!val) { 00917 release_sock(sk); 00918 return -ENOTCONN; 00919 } 00920 break; 00921 } 00922 case IP_RECVERR: 00923 val=sk->protinfo.af_inet.recverr; 00924 break; 00925 case IP_MULTICAST_TTL: 00926 val=sk->protinfo.af_inet.mc_ttl; 00927 break; 00928 case IP_MULTICAST_LOOP: 00929 val=sk->protinfo.af_inet.mc_loop; 00930 break; 00931 case IP_MULTICAST_IF: 00932 { 00933 struct in_addr addr; 00934 len = min_t(unsigned int, len, sizeof(struct in_addr)); 00935 addr.s_addr = sk->protinfo.af_inet.mc_addr; 00936 release_sock(sk); 00937 00938 if(put_user(len, optlen)) 00939 return -EFAULT; 00940 if(copy_to_user((void *)optval, &addr, len)) 00941 return -EFAULT; 00942 return 0; 00943 } 00944 case IP_MSFILTER: 00945 { 00946 struct ip_msfilter msf; 00947 int err; 00948 00949 if (len < IP_MSFILTER_SIZE(0)) { 00950 release_sock(sk); 00951 return -EINVAL; 00952 } 00953 if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) { 00954 release_sock(sk); 00955 return -EFAULT; 00956 } 00957 err = ip_mc_msfget(sk, &msf, 00958 (struct ip_msfilter *)optval, optlen); 00959 release_sock(sk); 00960 return err; 00961 } 00962 case MCAST_MSFILTER: 00963 { 00964 struct group_filter gsf; 00965 int err; 00966 00967 if (len < GROUP_FILTER_SIZE(0)) { 00968 release_sock(sk); 00969 return -EINVAL; 00970 } 00971 if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) { 00972 release_sock(sk); 00973 return -EFAULT; 00974 } 00975 err = ip_mc_gsfget(sk, &gsf, 00976 (struct group_filter *)optval, optlen); 00977 release_sock(sk); 00978 return err; 00979 } 00980 case IP_PKTOPTIONS: 00981 { 00982 struct msghdr msg; 00983 00984 release_sock(sk); 00985 00986 if (sk->type != SOCK_STREAM) 00987 return -ENOPROTOOPT; 00988 00989 msg.msg_control = optval; 00990 msg.msg_controllen = len; 00991 msg.msg_flags = 0; 00992 00993 if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_PKTINFO) { 00994 struct in_pktinfo info; 00995 00996 info.ipi_addr.s_addr = sk->rcv_saddr; 00997 info.ipi_spec_dst.s_addr = sk->rcv_saddr; 00998 info.ipi_ifindex = sk->protinfo.af_inet.mc_index; 00999 put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info); 01000 } 01001 if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_TTL) { 01002 int hlim = sk->protinfo.af_inet.mc_ttl; 01003 put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim); 01004 } 01005 len -= msg.msg_controllen; 01006 return put_user(len, optlen); 01007 } 01008 case IP_FREEBIND: 01009 val = sk->protinfo.af_inet.freebind; 01010 break; 01011 default: 01012 #ifdef CONFIG_NETFILTER 01013 val = nf_getsockopt(sk, PF_INET, optname, optval, 01014 &len); 01015 release_sock(sk); 01016 if (val >= 0) 01017 val = put_user(len, optlen); 01018 return val; 01019 #else 01020 release_sock(sk); 01021 return -ENOPROTOOPT; 01022 #endif 01023 } 01024 release_sock(sk); 01025 01026 if (len < sizeof(int) && len > 0 && val>=0 && val<255) { 01027 unsigned char ucval = (unsigned char)val; 01028 len = 1; 01029 if(put_user(len, optlen)) 01030 return -EFAULT; 01031 if(copy_to_user(optval,&ucval,1)) 01032 return -EFAULT; 01033 } else { 01034 len = min_t(unsigned int, sizeof(int), len); 01035 if(put_user(len, optlen)) 01036 return -EFAULT; 01037 if(copy_to_user(optval,&val,len)) 01038 return -EFAULT; 01039 } 01040 return 0; 01041 }

Generated on Wed Dec 1 21:25:31 2004 for Linux 2.4.23 Networking by doxygen 1.3.8