📄 ip_sockglue.c
字号:
/* If optlen==0, it is equivalent to val == 0 */#ifdef CONFIG_IP_MROUTE if (optname >= MRT_BASE && optname <= (MRT_BASE + 10)) return ip_mroute_setsockopt(sk,optname,optval,optlen);#endif err = 0; lock_sock(sk); switch (optname) { case IP_OPTIONS: { struct ip_options * opt = NULL; if (optlen > 40 || optlen < 0) goto e_inval; err = ip_options_get(&opt, optval, optlen, 1); if (err) break; if (sk->type == SOCK_STREAM) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) if (sk->family == PF_INET || (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE)) && sk->daddr != LOOPBACK4_IPV6)) {#endif if (opt) tp->ext_header_len = opt->optlen; tcp_sync_mss(sk, tp->pmtu_cookie);#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) }#endif } opt = xchg(&sk->protinfo.af_inet.opt, opt); if (opt) kfree(opt); break; } case IP_PKTINFO: if (val) sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_PKTINFO; else sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_PKTINFO; break; case IP_RECVTTL: if (val) sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_TTL; else sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TTL; break; case IP_RECVTOS: if (val) sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_TOS; else sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_TOS; break; case IP_RECVOPTS: if (val) sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_RECVOPTS; else sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RECVOPTS; break; case IP_RETOPTS: if (val) sk->protinfo.af_inet.cmsg_flags |= IP_CMSG_RETOPTS; else sk->protinfo.af_inet.cmsg_flags &= ~IP_CMSG_RETOPTS; break; case IP_TOS: /* This sets both TOS and Precedence */ if (sk->type == SOCK_STREAM) { val &= ~3; val |= sk->protinfo.af_inet.tos & 3; } if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && !capable(CAP_NET_ADMIN)) { err = -EPERM; break; } if (sk->protinfo.af_inet.tos != val) { sk->protinfo.af_inet.tos=val; sk->priority = rt_tos2priority(val); sk_dst_reset(sk); } break; case IP_TTL: if (optlen<1) goto e_inval; if(val==-1) val = sysctl_ip_default_ttl; if(val<1||val>255) goto e_inval; sk->protinfo.af_inet.ttl=val; break; case IP_HDRINCL: if(sk->type!=SOCK_RAW) { err = -ENOPROTOOPT; break; } sk->protinfo.af_inet.hdrincl=val?1:0; break; case IP_MTU_DISCOVER: if (val<0 || val>2) goto e_inval; sk->protinfo.af_inet.pmtudisc = val; break; case IP_RECVERR: sk->protinfo.af_inet.recverr = !!val; if (!val) skb_queue_purge(&sk->error_queue); break; case IP_MULTICAST_TTL: if (sk->type == SOCK_STREAM) goto e_inval; if (optlen<1) goto e_inval; if (val==-1) val = 1; if (val < 0 || val > 255) goto e_inval; sk->protinfo.af_inet.mc_ttl=val; break; case IP_MULTICAST_LOOP: if (optlen<1) goto e_inval; sk->protinfo.af_inet.mc_loop = val ? 1 : 0; break; case IP_MULTICAST_IF: { struct ip_mreqn mreq; struct net_device *dev = NULL; if (sk->type == SOCK_STREAM) goto e_inval; /* * Check the arguments are allowable */ err = -EFAULT; if (optlen >= sizeof(struct ip_mreqn)) { if (copy_from_user(&mreq,optval,sizeof(mreq))) break; } else { memset(&mreq, 0, sizeof(mreq)); if (optlen >= sizeof(struct in_addr) && copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr))) break; } if (!mreq.imr_ifindex) { if (mreq.imr_address.s_addr == INADDR_ANY) { sk->protinfo.af_inet.mc_index = 0; sk->protinfo.af_inet.mc_addr = 0; err = 0; break; } dev = ip_dev_find(mreq.imr_address.s_addr); if (dev) { mreq.imr_ifindex = dev->ifindex; dev_put(dev); } } else dev = __dev_get_by_index(mreq.imr_ifindex); err = -EADDRNOTAVAIL; if (!dev) break; err = -EINVAL; if (sk->bound_dev_if && mreq.imr_ifindex != sk->bound_dev_if) break; sk->protinfo.af_inet.mc_index = mreq.imr_ifindex; sk->protinfo.af_inet.mc_addr = mreq.imr_address.s_addr; err = 0; break; } case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: { struct ip_mreqn mreq; if (optlen < sizeof(struct ip_mreq)) goto e_inval; err = -EFAULT; if (optlen >= sizeof(struct ip_mreqn)) { if(copy_from_user(&mreq,optval,sizeof(mreq))) break; } else { memset(&mreq, 0, sizeof(mreq)); if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq))) break; } if (optname == IP_ADD_MEMBERSHIP) err = ip_mc_join_group(sk,&mreq); else err = ip_mc_leave_group(sk,&mreq); break; } case IP_ROUTER_ALERT: err = ip_ra_control(sk, val ? 1 : 0, NULL); break; case IP_FREEBIND: if (optlen<1) goto e_inval; sk->protinfo.af_inet.freebind = !!val; break; default:#ifdef CONFIG_NETFILTER err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);#else err = -ENOPROTOOPT;#endif break; } release_sock(sk); return err;e_inval: release_sock(sk); return -EINVAL;}/* * Get the options. Note for future reference. The GET of IP options gets the * _received_ ones. The set sets the _sent_ ones. */int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen){ int val; int len; if(level!=SOL_IP) return -EOPNOTSUPP;#ifdef CONFIG_IP_MROUTE if(optname>=MRT_BASE && optname <=MRT_BASE+10) { return ip_mroute_getsockopt(sk,optname,optval,optlen); }#endif if(get_user(len,optlen)) return -EFAULT; if(len < 0) return -EINVAL; lock_sock(sk); switch(optname) { case IP_OPTIONS: { unsigned char optbuf[sizeof(struct ip_options)+40]; struct ip_options * opt = (struct ip_options*)optbuf; opt->optlen = 0; if (sk->protinfo.af_inet.opt) memcpy(optbuf, sk->protinfo.af_inet.opt, sizeof(struct ip_options)+ sk->protinfo.af_inet.opt->optlen); release_sock(sk); if (opt->optlen == 0) return put_user(0, optlen); ip_options_undo(opt); len = min_t(unsigned int, len, opt->optlen); if(put_user(len, optlen)) return -EFAULT; if(copy_to_user(optval, opt->__data, len)) return -EFAULT; return 0; } case IP_PKTINFO: val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_PKTINFO) != 0; break; case IP_RECVTTL: val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TTL) != 0; break; case IP_RECVTOS: val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_TOS) != 0; break; case IP_RECVOPTS: val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RECVOPTS) != 0; break; case IP_RETOPTS: val = (sk->protinfo.af_inet.cmsg_flags & IP_CMSG_RETOPTS) != 0; break; case IP_TOS: val=sk->protinfo.af_inet.tos; break; case IP_TTL: val=sk->protinfo.af_inet.ttl; break; case IP_HDRINCL: val=sk->protinfo.af_inet.hdrincl; break; case IP_MTU_DISCOVER: val=sk->protinfo.af_inet.pmtudisc; break; case IP_MTU: { struct dst_entry *dst; val = 0; dst = sk_dst_get(sk); if (dst) { val = dst->pmtu; dst_release(dst); } if (!val) { release_sock(sk); return -ENOTCONN; } break; } case IP_RECVERR: val=sk->protinfo.af_inet.recverr; break; case IP_MULTICAST_TTL: val=sk->protinfo.af_inet.mc_ttl; break; case IP_MULTICAST_LOOP: val=sk->protinfo.af_inet.mc_loop; break; case IP_MULTICAST_IF: { struct in_addr addr; len = min_t(unsigned int, len, sizeof(struct in_addr)); addr.s_addr = sk->protinfo.af_inet.mc_addr; release_sock(sk); if(put_user(len, optlen)) return -EFAULT; if(copy_to_user((void *)optval, &addr, len)) return -EFAULT; return 0; } case IP_PKTOPTIONS: { struct msghdr msg; release_sock(sk); if (sk->type != SOCK_STREAM) return -ENOPROTOOPT; msg.msg_control = optval; msg.msg_controllen = len; msg.msg_flags = 0; if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_PKTINFO) { struct in_pktinfo info; info.ipi_addr.s_addr = sk->rcv_saddr; info.ipi_spec_dst.s_addr = sk->rcv_saddr; info.ipi_ifindex = sk->protinfo.af_inet.mc_index; put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info); } if (sk->protinfo.af_inet.cmsg_flags&IP_CMSG_TTL) { int hlim = sk->protinfo.af_inet.mc_ttl; put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim); } len -= msg.msg_controllen; return put_user(len, optlen); } case IP_FREEBIND: val = sk->protinfo.af_inet.freebind; break; default:#ifdef CONFIG_NETFILTER val = nf_getsockopt(sk, PF_INET, optname, optval, &len); release_sock(sk); if (val >= 0) val = put_user(len, optlen); return val;#else release_sock(sk); return -ENOPROTOOPT;#endif } release_sock(sk); if (len < sizeof(int) && len > 0 && val>=0 && val<255) { unsigned char ucval = (unsigned char)val; len = 1; if(put_user(len, optlen)) return -EFAULT; if(copy_to_user(optval,&ucval,1)) return -EFAULT; } else { len = min_t(unsigned int, sizeof(int), len); if(put_user(len, optlen)) return -EFAULT; if(copy_to_user(optval,&val,len)) return -EFAULT; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -