📄 raw.c
字号:
csum = (__u16 *) (buff + opt->offset); *csum = hdr->cksum; } else { if (net_ratelimit()) printk(KERN_DEBUG "icmp: cksum offset too big\n"); return -EINVAL; } } return 0; }static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len){ struct ipv6_txoptions opt_space; struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name; struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; struct ipv6_txoptions *opt = NULL; struct ip6_flowlabel *flowlabel = NULL; struct flowi fl; int addr_len = msg->msg_namelen; struct in6_addr *daddr; struct raw6_opt *raw_opt; int hlimit = -1; u16 proto; int err; /* Rough check on arithmetic overflow, better check is made in ip6_build_xmit */ if (len < 0) return -EMSGSIZE; /* Mirror BSD error message compatibility */ if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; /* * Get and verify the address. */ fl.fl6_flowlabel = 0; fl.oif = 0; if (sin6) { if (addr_len < SIN6_LEN_RFC2133) return -EINVAL; if (sin6->sin6_family && sin6->sin6_family != AF_INET6) return(-EINVAL); /* port is the proto value [0..255] carried in nexthdr */ proto = ntohs(sin6->sin6_port); if (!proto) proto = sk->num; if (proto > 255) return(-EINVAL); daddr = &sin6->sin6_addr; if (np->sndflow) { fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); if (flowlabel == NULL) return -EINVAL; daddr = &flowlabel->dst; } } /* Otherwise it will be difficult to maintain sk->dst_cache. */ if (sk->state == TCP_ESTABLISHED && !ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr)) daddr = &sk->net_pinfo.af_inet6.daddr; if (addr_len >= sizeof(struct sockaddr_in6) && sin6->sin6_scope_id && ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) fl.oif = sin6->sin6_scope_id; } else { if (sk->state != TCP_ESTABLISHED) return(-EINVAL); proto = sk->num; daddr = &(sk->net_pinfo.af_inet6.daddr); fl.fl6_flowlabel = np->flow_label; } if (ipv6_addr_any(daddr)) { /* * unspecfied destination address * treated as error... is this correct ? */ return(-EINVAL); } if (fl.oif == 0) fl.oif = sk->bound_dev_if; fl.fl6_src = NULL; if (msg->msg_controllen) { opt = &opt_space; memset(opt, 0, sizeof(struct ipv6_txoptions)); err = datagram_send_ctl(msg, &fl, opt, &hlimit); if (err < 0) { fl6_sock_release(flowlabel); return err; } if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); if (flowlabel == NULL) return -EINVAL; } if (!(opt->opt_nflen|opt->opt_flen)) opt = NULL; } if (opt == NULL) opt = np->opt; if (flowlabel) opt = fl6_merge_options(&opt_space, flowlabel, opt); raw_opt = &sk->tp_pinfo.tp_raw; fl.proto = proto; fl.fl6_dst = daddr; if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr)) fl.fl6_src = &np->saddr; fl.uli_u.icmpt.type = 0; fl.uli_u.icmpt.code = 0; if (raw_opt->checksum) { struct rawv6_fakehdr hdr; hdr.iov = msg->msg_iov; hdr.sk = sk; hdr.len = len; hdr.cksum = 0; hdr.proto = proto; if (opt && opt->srcrt) hdr.daddr = daddr; else hdr.daddr = NULL; err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len, opt, hlimit, msg->msg_flags); } else { err = ip6_build_xmit(sk, rawv6_getfrag, msg->msg_iov, &fl, len, opt, hlimit, msg->msg_flags); } fl6_sock_release(flowlabel); return err<0?err:len;}static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, char *optval, int optlen){ switch (optname) { case ICMPV6_FILTER: if (optlen > sizeof(struct icmp6_filter)) optlen = sizeof(struct icmp6_filter); if (copy_from_user(&sk->tp_pinfo.tp_raw.filter, optval, optlen)) return -EFAULT; return 0; default: return -ENOPROTOOPT; }; return 0;}static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, char *optval, int *optlen){ int len; switch (optname) { case ICMPV6_FILTER: if (get_user(len, optlen)) return -EFAULT; if (len < 0) return -EINVAL; if (len > sizeof(struct icmp6_filter)) len = sizeof(struct icmp6_filter); if (put_user(len, optlen)) return -EFAULT; if (copy_to_user(optval, &sk->tp_pinfo.tp_raw.filter, len)) return -EFAULT; return 0; default: return -ENOPROTOOPT; }; return 0;}static int rawv6_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen){ struct raw6_opt *opt = &sk->tp_pinfo.tp_raw; int val; switch(level) { case SOL_RAW: break; case SOL_ICMPV6: if (sk->num != IPPROTO_ICMPV6) return -EOPNOTSUPP; return rawv6_seticmpfilter(sk, level, optname, optval, optlen); case SOL_IPV6: if (optname == IPV6_CHECKSUM) break; default: return ipv6_setsockopt(sk, level, optname, optval, optlen); }; if (get_user(val, (int *)optval)) return -EFAULT; switch (optname) { case IPV6_CHECKSUM: if (val < 0) { opt->checksum = 0; } else { opt->checksum = 1; opt->offset = val; } return 0; break; default: return(-ENOPROTOOPT); }}static int rawv6_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen){ struct raw6_opt *opt = &sk->tp_pinfo.tp_raw; int val, len; switch(level) { case SOL_RAW: break; case SOL_ICMPV6: if (sk->num != IPPROTO_ICMPV6) return -EOPNOTSUPP; return rawv6_geticmpfilter(sk, level, optname, optval, optlen); case SOL_IPV6: if (optname == IPV6_CHECKSUM) break; default: return ipv6_getsockopt(sk, level, optname, optval, optlen); }; if (get_user(len,optlen)) return -EFAULT; switch (optname) { case IPV6_CHECKSUM: if (opt->checksum == 0) val = -1; else val = opt->offset; default: return -ENOPROTOOPT; } 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;}static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg){ switch(cmd) { case SIOCOUTQ: { int amount = atomic_read(&sk->wmem_alloc); return put_user(amount, (int *)arg); } case SIOCINQ: { struct sk_buff *skb; int amount = 0; spin_lock_irq(&sk->receive_queue.lock); skb = skb_peek(&sk->receive_queue); if (skb != NULL) amount = skb->tail - skb->h.raw; spin_unlock_irq(&sk->receive_queue.lock); return put_user(amount, (int *)arg); } default: return -ENOIOCTLCMD; }}static void rawv6_close(struct sock *sk, long timeout){ if (sk->num == IPPROTO_RAW) ip6_ra_control(sk, -1, NULL); inet_sock_release(sk);}static int rawv6_init_sk(struct sock *sk){ return(0);}#define LINE_LEN 190#define LINE_FMT "%-190s\n"static void get_raw6_sock(struct sock *sp, char *tmpbuf, int i){ struct in6_addr *dest, *src; __u16 destp, srcp; dest = &sp->net_pinfo.af_inet6.daddr; src = &sp->net_pinfo.af_inet6.rcv_saddr; destp = 0; srcp = sp->num; sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p", i, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), atomic_read(&sp->refcnt), sp);}int raw6_get_info(char *buffer, char **start, off_t offset, int length){ int len = 0, num = 0, i; off_t pos = 0; off_t begin; char tmpbuf[LINE_LEN+2]; if (offset < LINE_LEN+1) len += sprintf(buffer, LINE_FMT, " sl " /* 6 */ "local_address " /* 38 */ "remote_address " /* 38 */ "st tx_queue rx_queue tr tm->when retrnsmt" /* 41 */ " uid timeout inode"); /* 21 */ /*----*/ /*144 */ pos = LINE_LEN+1; read_lock(&raw_v6_lock); for (i = 0; i < RAWV6_HTABLE_SIZE; i++) { struct sock *sk; for (sk = raw_v6_htable[i]; sk; sk = sk->next, num++) { if (sk->family != PF_INET6) continue; pos += LINE_LEN+1; if (pos <= offset) continue; get_raw6_sock(sk, tmpbuf, i); len += sprintf(buffer+len, LINE_FMT, tmpbuf); if(len >= length) goto out; } }out: read_unlock(&raw_v6_lock); begin = len - (pos - offset); *start = buffer + begin; len -= begin; if(len > length) len = length; if (len < 0) len = 0; return len;}struct proto rawv6_prot = { name: "RAW", close: rawv6_close, connect: udpv6_connect, disconnect: udp_disconnect, ioctl: rawv6_ioctl, init: rawv6_init_sk, destroy: inet6_destroy_sock, setsockopt: rawv6_setsockopt, getsockopt: rawv6_getsockopt, sendmsg: rawv6_sendmsg, recvmsg: rawv6_recvmsg, bind: rawv6_bind, backlog_rcv: rawv6_rcv_skb, hash: raw_v6_hash, unhash: raw_v6_unhash,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -