diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
commit | 3917ac5846dd0f9ad1238166f90caab9912052e6 (patch) | |
tree | 1c298935def4f29edb39192365a65d73de999155 /net | |
parent | af2f803c8b2d469fe38e4a7ce952658dfcb6681a (diff) |
o Merge with Linux 2.1.100.
o Cleanup the machine dependencies of floppy and rtc. The driver for
the Dallas thingy in the Indy is still missing.
o Handle allocation of zero'd pages correct for R4000SC / R4400SC.
o Page colouring shit to match the virtual and physical colour of all
mapped pages. This tends to produce extreme fragmentation problems,
so it's deactivated for now. Users of R4000SC / R4400SC may re-enable
the code in arch/mips/mm/init.c by removing the definition of
CONF_GIVE_A_SHIT_ABOUT_COLOURS. Should get them somewhat further -
but don't shake to hard ...
o Fixed ptrace(2)-ing of syscalls, strace is now working again.
o Fix the interrupt forwarding from the keyboard driver to the psaux
driver, PS/2 mice are now working on the Indy. The fix is somewhat
broken as it prevents generic kernels for Indy and machines which handle
things different.
o Things I can't remember.
Diffstat (limited to 'net')
-rw-r--r-- | net/appletalk/ddp.c | 6 | ||||
-rw-r--r-- | net/core/dev.c | 10 | ||||
-rw-r--r-- | net/core/scm.c | 17 | ||||
-rw-r--r-- | net/core/sock.c | 4 | ||||
-rw-r--r-- | net/ethernet/pe2.c | 3 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 9 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 4 | ||||
-rw-r--r-- | net/ipv4/fib_frontend.c | 2 | ||||
-rw-r--r-- | net/ipv4/ip_fw.c | 153 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 9 | ||||
-rw-r--r-- | net/ipv4/raw.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 53 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 38 | ||||
-rw-r--r-- | net/ipv4/tcp_timer.c | 12 | ||||
-rw-r--r-- | net/ipv4/udp.c | 2 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 4 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 7 | ||||
-rw-r--r-- | net/ipv6/exthdrs.c | 81 | ||||
-rw-r--r-- | net/ipv6/icmp.c | 156 | ||||
-rw-r--r-- | net/ipv6/ip6_input.c | 8 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 4 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 10 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 3 | ||||
-rw-r--r-- | net/ipv6/reassembly.c | 79 | ||||
-rw-r--r-- | net/ipv6/route.c | 2 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 23 | ||||
-rw-r--r-- | net/netsyms.c | 2 | ||||
-rw-r--r-- | net/packet/af_packet.c | 5 | ||||
-rw-r--r-- | net/rose/af_rose.c | 2 | ||||
-rw-r--r-- | net/wanrouter/wanmain.c | 2 | ||||
-rw-r--r-- | net/x25/af_x25.c | 2 |
31 files changed, 450 insertions, 264 deletions
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index c56adc148..b85835f47 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -719,7 +719,7 @@ int atif_ioctl(int cmd, void *arg) switch(cmd) { case SIOCSIFADDR: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return (-EPERM); if(sa->sat_family != AF_APPLETALK) return (-EINVAL); @@ -830,7 +830,7 @@ int atif_ioctl(int cmd, void *arg) case SIOCATALKDIFADDR: case SIOCDIFADDR: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return (-EPERM); if(sa->sat_family != AF_APPLETALK) return (-EINVAL); @@ -1809,7 +1809,7 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) */ case SIOCADDRT: case SIOCDELRT: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return -EPERM; return (atrtr_ioctl(cmd,(void *)arg)); diff --git a/net/core/dev.c b/net/core/dev.c index 85312b12c..69315d948 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -321,7 +321,7 @@ struct device *dev_alloc(const char *name, int *err) void dev_load(const char *name) { - if(!dev_get(name) && suser()) + if(!dev_get(name) && capable(CAP_SYS_MODULE)) request_module(name); } @@ -1591,7 +1591,7 @@ int dev_ioctl(unsigned int cmd, void *arg) case SIOCDELMULTI: case SIOCSIFHWBROADCAST: case SIOCSIFTXQLEN: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; dev_load(ifr.ifr_name); rtnl_lock(); @@ -1764,6 +1764,9 @@ extern int baycom_init(void); extern int lapbeth_init(void); extern void arcnet_init(void); extern void ip_auto_config(void); +#ifdef CONFIG_8xx +extern int cpm_enet_init(void); +#endif /* CONFIG_8xx */ #ifdef CONFIG_PROC_FS static struct proc_dir_entry proc_net_dev = { @@ -1846,6 +1849,9 @@ __initfunc(int net_dev_init(void)) #if defined(CONFIG_ARCNET) arcnet_init(); #endif +#if defined(CONFIG_8xx) + cpm_enet_init(); +#endif /* * SLHC if present needs attaching so other people see it * even if not opened. diff --git a/net/core/scm.c b/net/core/scm.c index ac4aefda0..dd19cf5e0 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -45,19 +45,16 @@ static __inline__ int scm_check_creds(struct ucred *creds) { - /* N.B. The test for suser should follow the credential check */ - if (suser()) + if ((creds->pid == current->pid || capable(CAP_SYS_ADMIN)) && + ((creds->uid == current->uid || creds->uid == current->euid || + creds->uid == current->suid) || capable(CAP_SETUID)) && + ((creds->gid == current->gid || creds->gid == current->egid || + creds->gid == current->sgid) || capable(CAP_SETGID))) { return 0; - if (creds->pid != current->pid || - (creds->uid != current->uid && creds->uid != current->euid && - creds->uid != current->suid) || - (creds->gid != current->gid && creds->gid != current->egid && - creds->gid != current->sgid)) - return -EPERM; - return 0; + } + return -EPERM; } - static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) { int *fdp = (int*)CMSG_DATA(cmsg); diff --git a/net/core/sock.c b/net/core/sock.c index 30e5d3e77..428b4052c 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -185,7 +185,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, switch(optname) { case SO_DEBUG: - if(val && !suser()) + if(val && !capable(CAP_NET_ADMIN)) { ret = -EACCES; } @@ -924,7 +924,7 @@ int sock_no_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) */ if (current->pgrp != -arg && current->pid != arg && - !suser()) return(-EPERM); + !capable(CAP_NET_ADMIN)) return(-EPERM); sk->proc = arg; return(0); case F_GETOWN: diff --git a/net/ethernet/pe2.c b/net/ethernet/pe2.c index 812d35864..4915f0707 100644 --- a/net/ethernet/pe2.c +++ b/net/ethernet/pe2.c @@ -11,7 +11,8 @@ pEII_datalink_header(struct datalink_proto *dl, struct device *dev = skb->dev; skb->protocol = htons (ETH_P_IPX); - dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len); + if(dev->hard_header) + dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len); } struct datalink_proto * diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index ce177c56b..a54ae8a95 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -374,7 +374,7 @@ static int inet_create(struct socket *sock, int protocol) sock->ops = &inet_dgram_ops; break; case SOCK_RAW: - if (!suser()) + if (!capable(CAP_NET_RAW)) goto free_and_badperm; if (!protocol) goto free_and_noproto; @@ -521,7 +521,7 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) #endif if (snum == 0) snum = sk->prot->good_socknum(); - if (snum < PROT_SOCK && !suser()) + if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return(-EACCES); chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); @@ -529,7 +529,7 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) { #ifdef CONFIG_IP_TRANSPARENT_PROXY /* Superuser may bind to any address to allow transparent proxying. */ - if(chk_addr_ret != RTN_UNICAST || !suser()) + if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN)) #endif return -EADDRNOTAVAIL; /* Source address MUST be ours! */ } @@ -868,7 +868,8 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) err = get_user(pid, (int *) arg); if (err) return err; - if (current->pid != pid && current->pgrp != -pid && !suser()) + if (current->pid != pid && current->pgrp != -pid && + !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; return(0); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 79eb9a1d4..47b5ef25c 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -435,7 +435,7 @@ int devinet_ioctl(unsigned int cmd, void *arg) break; case SIOCSIFFLAGS: - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EACCES; rtnl_lock(); exclusive = 1; @@ -444,7 +444,7 @@ int devinet_ioctl(unsigned int cmd, void *arg) case SIOCSIFBRDADDR: /* Set the broadcast address */ case SIOCSIFDSTADDR: /* Set the destination address */ case SIOCSIFNETMASK: /* Set the netmask for the interface */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EACCES; if (sin->sin_family != AF_INET) return -EINVAL; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 6350a6366..24f3052fe 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -253,7 +253,7 @@ int ip_rt_ioctl(unsigned int cmd, void *arg) switch (cmd) { case SIOCADDRT: /* Add a route */ case SIOCDELRT: /* Delete a route */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&r, arg, sizeof(struct rtentry))) return -EFAULT; diff --git a/net/ipv4/ip_fw.c b/net/ipv4/ip_fw.c index b364f66de..745d07cb4 100644 --- a/net/ipv4/ip_fw.c +++ b/net/ipv4/ip_fw.c @@ -6,7 +6,7 @@ * license in recognition of the original copyright. * -- Alan Cox. * - * $Id: ip_fw.c,v 1.4 1998/03/17 22:18:25 ralf Exp $ + * $Id: ip_fw.c,v 1.35 1998/04/30 16:29:51 freitag Exp $ * * Ported from BSD to Linux, * Alan Cox 22/Nov/1994. @@ -62,6 +62,7 @@ * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands * * Juan Jose Ciarlante : Masquerading code moved to ip_masq.c + * Andi Kleen : Print frag_offsets and the ip flags properly. * * All the real work was done by ..... * @@ -202,6 +203,90 @@ extern inline int port_match(unsigned short *portptr,int nports,unsigned short p #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) +#ifdef CONFIG_IP_FIREWALL_VERBOSE + +/* + * VERY ugly piece of code which actually makes kernel printf for + * matching packets. + */ + +static char *chain_name(struct ip_fw *chain, int mode) +{ + switch (mode) { + case IP_FW_MODE_ACCT_IN: return "acct in"; + case IP_FW_MODE_ACCT_OUT: return "acct out"; + default: + if (chain == ip_fw_fwd_chain) + return "fw-fwd"; + else if (chain == ip_fw_in_chain) + return "fw-in"; + else + return "fw-out"; + } +} + +static char *rule_name(struct ip_fw *f, int mode, char *buf) +{ + if (mode == IP_FW_MODE_ACCT_IN || mode == IP_FW_MODE_ACCT_OUT) + return ""; + + if(f->fw_flg&IP_FW_F_ACCEPT) { + if(f->fw_flg&IP_FW_F_REDIR) { + sprintf(buf, "acc/r%d ", f->fw_pts[f->fw_nsp+f->fw_ndp]); + return buf; + } else if(f->fw_flg&IP_FW_F_MASQ) + return "acc/masq "; + else + return "acc "; + } else if(f->fw_flg&IP_FW_F_ICMPRPL) { + return "rej "; + } else { + return "deny "; + } +} + +static void print_packet(struct iphdr *ip, + u16 src_port, u16 dst_port, u16 icmp_type, + char *chain, char *rule, char *devname) +{ + __u32 *opt = (__u32 *) (ip + 1); + int opti; + __u16 foff = ntohs(ip->frag_off); + + printk(KERN_INFO "IP %s %s%s", chain, rule, devname); + + switch(ip->protocol) + { + case IPPROTO_TCP: + printk(" TCP "); + break; + case IPPROTO_UDP: + printk(" UDP "); + break; + case IPPROTO_ICMP: + printk(" ICMP/%d ", icmp_type); + break; + default: + printk(" PROTO=%d ", ip->protocol); + break; + } + print_ip(ip->saddr); + if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) + printk(":%hu", src_port); + printk(" "); + print_ip(ip->daddr); + if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) + printk(":%hu", dst_port); + printk(" L=%hu S=0x%2.2hX I=%hu FO=0x%4.4hX T=%hu", + ntohs(ip->tot_len), ip->tos, ntohs(ip->id), + foff & IP_OFFSET, ip->ttl); + if (foff & IP_DF) printk(" DF=1"); + if (foff & IP_MF) printk(" MF=1"); + for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++) + printk(" O=0x%8.8X", *opt++); + printk("\n"); +} +#endif /* * Returns one of the generic firewall policies, like FW_ACCEPT. @@ -483,68 +568,14 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, __u16 *redirport, struct ip_ } #ifdef CONFIG_IP_FIREWALL_VERBOSE - /* - * VERY ugly piece of code which actually - * makes kernel printf for matching packets... - */ - if (f->fw_flg & IP_FW_F_PRN) { - __u32 *opt = (__u32 *) (ip + 1); - int opti; - - if(mode == IP_FW_MODE_ACCT_IN) - printk(KERN_INFO "IP acct in "); - else if(mode == IP_FW_MODE_ACCT_OUT) - printk(KERN_INFO "IP acct out "); - else { - if(chain == ip_fw_fwd_chain) - printk(KERN_INFO "IP fw-fwd "); - else if(chain == ip_fw_in_chain) - printk(KERN_INFO "IP fw-in "); - else - printk(KERN_INFO "IP fw-out "); - if(f->fw_flg&IP_FW_F_ACCEPT) { - if(f->fw_flg&IP_FW_F_REDIR) - printk("acc/r%d ", f->fw_pts[f->fw_nsp+f->fw_ndp]); - else if(f->fw_flg&IP_FW_F_MASQ) - printk("acc/masq "); - else - printk("acc "); - } else if(f->fw_flg&IP_FW_F_ICMPRPL) - printk("rej "); - else - printk("deny "); - } - printk(rif ? rif->name : "-"); - switch(ip->protocol) - { - case IPPROTO_TCP: - printk(" TCP "); - break; - case IPPROTO_UDP: - printk(" UDP "); - break; - case IPPROTO_ICMP: - printk(" ICMP/%d ", icmp_type); - break; - default: - printk(" PROTO=%d ", ip->protocol); - break; - } - print_ip(ip->saddr); - if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) - printk(":%hu", src_port); - printk(" "); - print_ip(ip->daddr); - if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) - printk(":%hu", dst_port); - printk(" L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu", - ntohs(ip->tot_len), ip->tos, ntohs(ip->id), - ip->frag_off, ip->ttl); - for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++) - printk(" O=0x%8.8X", *opt++); - printk("\n"); + char buf[16]; + + print_packet(ip, src_port, dst_port, icmp_type, + chain_name(chain, mode), + rule_name(f, mode, buf), + rif ? rif->name : "-"); } #endif if (mode != IP_FW_MODE_CHK) { diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 1b7f44e8f..b31a1d3a0 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -311,7 +311,8 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt /* Reject setting of unused bits */ if (val & ~(IPTOS_TOS_MASK|IPTOS_PREC_MASK)) return -EINVAL; - if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && !suser()) + if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && + !capable(CAP_NET_ADMIN)) return -EPERM; if (sk->ip_tos != val) { sk->ip_tos=val; @@ -453,7 +454,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt case IP_FW_POLICY_OUT: case IP_FW_POLICY_FWD: case IP_FW_MASQ_TIMEOUTS: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return -EACCES; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; @@ -467,7 +468,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt case IP_FW_MASQ_ADD: case IP_FW_MASQ_DEL: case IP_FW_MASQ_FLUSH: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return -EPERM; if(optlen>sizeof(masq_ctl) || optlen<1) return -EINVAL; @@ -483,7 +484,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt case IP_ACCT_DELETE: case IP_ACCT_FLUSH: case IP_ACCT_ZERO: - if(!suser()) + if(!capable(CAP_NET_ADMIN)) return -EACCES; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index baebab777..a73f12a49 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -398,7 +398,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) { #ifdef CONFIG_IP_TRANSPARENT_PROXY /* Superuser may bind to any address to allow transparent proxying. */ - if(chk_addr_ret != RTN_UNICAST || !suser()) + if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN)) #endif return -EADDRNOTAVAIL; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d5b0b15c6..7a0a40aeb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.114 1998/04/28 06:42:22 davem Exp $ + * Version: $Id: tcp_input.c,v 1.116 1998/05/02 14:50:11 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -421,33 +421,6 @@ static __inline__ int tcp_fast_parse_options(struct sock *sk, struct tcphdr *th, return 1; } -#if 0 /* Not working yet... -DaveM */ -static void tcp_compute_tsack(struct sock *sk, struct tcp_opt *tp) -{ - struct sk_buff *skb = skb_peek(&sk->write_queue); - __u32 tstamp = tp->rcv_tsecr; - int fack_count = 0; - - while((skb != NULL) && - (skb != tp->send_head) && - (skb != (struct sk_buff *)&sk->write_queue)) { - if(TCP_SKB_CB(skb)->when == tstamp) { - __u8 sacked = TCP_SKB_CB(skb)->sacked; - - sacked |= TCPCB_SACKED_ACKED; - if(sacked & TCPCB_SACKED_RETRANS) - tp->retrans_out--; - TCP_SKB_CB(skb)->sacked = sacked; - } - if(!before(TCP_SKB_CB(skb)->when, tstamp)) - fack_count++; - skb = skb->next; - } - if(fack_count > tp->fackets_out) - tp->fackets_out = fack_count; -} -#endif - #define FLAG_DATA 0x01 /* Incoming frame contained data. */ #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ #define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ @@ -481,13 +454,6 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup) if (ack == tp->snd_una && tp->packets_out && (not_dup == 0)) { /* This is the standard reno style fast retransmit branch. */ -#if 0 /* Not working yet... -DaveM */ - /* If not doing SACK, but doing timestamps, compute timestamp - * based pseudo-SACKs when we see duplicate ACKs. - */ - if(!tp->sack_ok && tp->saw_tstamp) - tcp_compute_tsack(sk, tp); -#endif /* 1. When the third duplicate ack is received, set ssthresh * to one half the current congestion window, but no less * than two segments. Retransmit the missing segment. @@ -611,6 +577,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head)) { struct tcp_skb_cb *scb = TCP_SKB_CB(skb); + __u8 sacked = scb->sacked; /* If our packet is before the ack sequence we can * discard it as it's confirmed to have arrived at @@ -626,22 +593,12 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, * connection startup slow start one packet too * quickly. This is severely frowned upon behavior. */ + if(sacked & TCPCB_SACKED_RETRANS && tp->retrans_out) + tp->retrans_out--; if(!(scb->flags & TCPCB_FLAG_SYN)) { - __u8 sacked = scb->sacked; - acked |= FLAG_DATA_ACKED; - if(sacked & TCPCB_SACKED_RETRANS) { + if(sacked & TCPCB_SACKED_RETRANS) acked |= FLAG_RETRANS_DATA_ACKED; - - /* XXX The race is, fast retrans frame --> - * XXX retrans timeout sends older frame --> - * XXX ACK arrives for fast retrans frame --> - * XXX retrans_out goes negative --> splat. - * XXX Please help me find a better way -DaveM - */ - if(tp->retrans_out) - tp->retrans_out--; - } if(tp->fackets_out) tp->fackets_out--; } else { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 08ca40a4b..328cc9389 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.142 1998/04/30 12:00:45 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.145 1998/05/02 12:47:13 davem Exp $ * * IPv4 specific functions * @@ -48,7 +48,6 @@ #include <linux/config.h> #include <linux/types.h> -#include <linux/stddef.h> #include <linux/fcntl.h> #include <linux/random.h> #include <linux/init.h> @@ -61,12 +60,15 @@ #include <asm/segment.h> #include <linux/inet.h> +#include <linux/stddef.h> extern int sysctl_tcp_timestamps; extern int sysctl_tcp_window_scaling; extern int sysctl_tcp_sack; extern int sysctl_tcp_syncookies; extern int sysctl_ip_dynaddr; +extern __u32 sysctl_wmem_max; +extern __u32 sysctl_rmem_max; /* Check TCP sequence numbers in ICMP packets. */ #define ICMP_MIN_LENGTH 8 @@ -166,17 +168,21 @@ struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum) return tb; } +#ifdef CONFIG_IP_TRANSPARENT_PROXY /* Ensure that the bound bucket for the port exists. * Return 0 on success. */ static __inline__ int tcp_bucket_check(unsigned short snum) { - if (tcp_bound_hash[tcp_bhashfn(snum)] == NULL && - tcp_bucket_create(snum) == NULL) + struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(snum)]; + for( ; (tb && (tb->port != snum)); tb = tb->next) + ; + if(tb == NULL && tcp_bucket_create(snum) == NULL) return 1; else return 0; } +#endif static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum) { @@ -215,10 +221,21 @@ static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum) result = 1; } } - if((result == 0) && - (tb == NULL) && - (tcp_bucket_create(snum) == NULL)) - result = 1; + if(result == 0) { + if(tb == NULL) { + if(tcp_bucket_create(snum) == NULL) + result = 1; + } else { + /* It could be pending garbage collection, this + * kills the race and prevents it from disappearing + * out from under us by the time we use it. -DaveM + */ + if(tb->owners == NULL && !(tb->flags & TCPB_FLAG_LOCKED)) { + tb->flags = TCPB_FLAG_LOCKED; + tcp_dec_slow_timer(TCP_SLT_BUCKETGC); + } + } + } go_like_smoke: SOCKHASH_UNLOCK(); return result; @@ -1308,6 +1325,11 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, if (!newsk) goto exit; + if (newsk->rcvbuf < (3 * newsk->mtu)) + newsk->rcvbuf = min ((3 * newsk->mtu), sysctl_rmem_max); + if (newsk->sndbuf < (3 * newsk->mtu)) + newsk->sndbuf = min ((3 * newsk->mtu), sysctl_wmem_max); + sk->tp_pinfo.af_tcp.syn_backlog--; sk->ack_backlog++; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 9bf74f472..665a448bb 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.6 1998/03/17 22:18:35 ralf Exp $ + * Version: $Id: tcp_timer.c,v 1.51 1998/05/02 15:19:26 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -448,26 +448,24 @@ void tcp_retransmit_timer(unsigned long data) */ if(tp->sack_ok) { struct sk_buff *skb = skb_peek(&sk->write_queue); - __u8 toclear = TCPCB_SACKED_ACKED; - if(tp->retransmits == 0) - toclear |= TCPCB_SACKED_RETRANS; while((skb != NULL) && (skb != tp->send_head) && (skb != (struct sk_buff *)&sk->write_queue)) { - TCP_SKB_CB(skb)->sacked &= ~(toclear); + TCP_SKB_CB(skb)->sacked &= + ~(TCPCB_SACKED_ACKED | TCPCB_SACKED_RETRANS); skb = skb->next; } - tp->fackets_out = 0; } /* Retransmission. */ tp->retrans_head = NULL; + tp->fackets_out = 0; + tp->retrans_out = 0; if (tp->retransmits == 0) { /* remember window where we lost * "one half of the current window but at least 2 segments" */ - tp->retrans_out = 0; tp->snd_ssthresh = max(tp->snd_cwnd >> (1 + TCP_CWND_SHIFT), 2); tp->snd_cwnd = (1 << TCP_CWND_SHIFT); } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a580b0010..d42dcc3d4 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -646,7 +646,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len) #ifdef CONFIG_IP_TRANSPARENT_PROXY if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT|MSG_PROXY|MSG_NOSIGNAL)) return -EINVAL; - if ((msg->msg_flags&MSG_PROXY) && !suser() ) + if ((msg->msg_flags&MSG_PROXY) && !capable(CAP_NET_ADMIN)) return -EPERM; #else if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT|MSG_NOSIGNAL)) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0241e0459..5571c04c7 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -894,7 +894,7 @@ int addrconf_add_ifaddr(void *arg) struct in6_ifreq ireq; int err; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) @@ -911,7 +911,7 @@ int addrconf_del_ifaddr(void *arg) struct in6_ifreq ireq; int err; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 902274ecb..c1b2e9d14 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -89,7 +89,7 @@ static int inet6_create(struct socket *sock, int protocol) prot=&udpv6_prot; sock->ops = &inet6_dgram_ops; } else if(sock->type == SOCK_RAW) { - if (!suser()) + if (!capable(CAP_NET_RAW)) goto free_and_badperm; if (!protocol) goto free_and_noproto; @@ -187,7 +187,7 @@ static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) snum = ntohs(addr->sin6_port); if (snum == 0) snum = sk->prot->good_socknum(); - if (snum < PROT_SOCK && !suser()) + if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return(-EACCES); addr_type = ipv6_addr_type(&addr->sin6_addr); @@ -291,7 +291,8 @@ static int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return err; /* see sock_no_fcntl */ - if (current->pid != pid && current->pgrp != -pid && !suser()) + if (current->pid != pid && current->pgrp != -pid && + !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; return(0); diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index af29057ec..0b826870f 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -4,8 +4,9 @@ * * Authors: * Pedro Roque <roque@di.fc.ul.pt> + * Andi Kleen <ak@muc.de> * - * $Id: exthdrs.c,v 1.5 1998/02/12 07:43:39 davem Exp $ + * $Id: exthdrs.c,v 1.6 1998/04/30 16:24:20 freitag Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,6 +35,10 @@ #include <net/ip6_route.h> #include <net/addrconf.h> +#include <asm/uaccess.h> + +#define swap(a,b) do { typeof (a) tmp; tmp = (a); (a) = (b); (b) = (tmp); } while(0) + /* * inbound */ @@ -135,7 +140,7 @@ int ipv6_routing_header(struct sk_buff **skb_ptr, struct device *dev, */ int ipv6opt_bld_rthdr(struct sk_buff *skb, struct ipv6_options *opt, - struct in6_addr *addr, int proto) + struct in6_addr *addr) { struct rt0_hdr *phdr, *ihdr; int hops; @@ -153,8 +158,76 @@ int ipv6opt_bld_rthdr(struct sk_buff *skb, struct ipv6_options *opt, ipv6_addr_copy(phdr->addr + (hops - 1), addr); - phdr->rt_hdr.nexthdr = proto; - + phdr->rt_hdr.nexthdr = proto; return NEXTHDR_ROUTING; } #endif + +/* + * find out if nexthdr is an extension header or a protocol + */ + +static __inline__ int ipv6_ext_hdr(u8 nexthdr) +{ + /* + * find out if nexthdr is an extension header or a protocol + */ + return ( (nexthdr == NEXTHDR_HOP) || + (nexthdr == NEXTHDR_ROUTING) || + (nexthdr == NEXTHDR_FRAGMENT) || + (nexthdr == NEXTHDR_ESP) || + (nexthdr == NEXTHDR_AUTH) || + (nexthdr == NEXTHDR_NONE) || + (nexthdr == NEXTHDR_DEST) ); + +} + +/* + * Skip any extension headers. This is used by the ICMP module. + * + * Note that strictly speaking this conflicts with RFC1883 4.0: + * ...The contents and semantics of each extension header determine whether + * or not to proceed to the next header. Therefore, extension headers must + * be processed strictly in the order they appear in the packet; a + * receiver must not, for example, scan through a packet looking for a + * particular kind of extension header and process that header prior to + * processing all preceding ones. + * + * We do exactly this. This is a protocol bug. We can't decide after a + * seeing an unknown discard-with-error flavour TLV option if it's a + * ICMP error message or not (errors should never be send in reply to + * ICMP error messages). + * + * But I see no other way to do this. This might need to be reexamined + * when Linux implements ESP (and maybe AUTH) headers. + */ +struct ipv6_opt_hdr *ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, + u8 *nexthdrp, int len) +{ + u8 nexthdr = *nexthdrp; + + while (ipv6_ext_hdr(nexthdr)) { + int hdrlen; + + if (nexthdr == NEXTHDR_NONE) + return NULL; + if (len < sizeof(struct ipv6_opt_hdr)) /* be anal today */ + return NULL; + + hdrlen = ipv6_optlen(hdr); + if (len < hdrlen) + return NULL; + + nexthdr = hdr->nexthdr; + hdr = (struct ipv6_opt_hdr *) ((u8*)hdr + hdrlen); + len -= hdrlen; + } + + /* Hack.. Do the same for AUTH headers? */ + if (nexthdr == NEXTHDR_ESP) + return NULL; + + *nexthdrp = nexthdr; + return hdr; +} + diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index f181aec52..104895936 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: icmp.c,v 1.15 1998/03/21 07:28:03 davem Exp $ + * $Id: icmp.c,v 1.17 1998/05/01 10:31:41 davem Exp $ * * Based on net/ipv4/icmp.c * @@ -21,6 +21,8 @@ * Changes: * * Andi Kleen : exception handling + * Andi Kleen add rate limits. never reply to a icmp. + * add more length checks and other fixes. */ #define __NO_VERSION__ @@ -51,6 +53,7 @@ #include <net/transp_v6.h> #include <net/ip6_route.h> #include <net/addrconf.h> +#include <net/icmp.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -129,6 +132,62 @@ static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, return 0; } + +/* + * Slightly more convenient version of icmpv6_send. + */ +void icmpv6_param_prob(struct sk_buff *skb, int code, void *pos) +{ + int offset = (u8*)pos - (u8*)skb->nh.ipv6h; + + icmpv6_send(skb, ICMPV6_PARAMPROB, code, offset, skb->dev); + kfree_skb(skb); +} + +static inline int is_icmp(struct ipv6hdr *hdr, int len) +{ + __u8 nexthdr = hdr->nexthdr; + + if (!ipv6_skip_exthdr((struct ipv6_opt_hdr *)(hdr+1), &nexthdr, len)) + return 0; + return nexthdr == IPPROTO_ICMP; +} + +int sysctl_icmpv6_time = 1*HZ; + +/* + * Check the ICMP output rate limit + */ +static inline int icmpv6_xrlim_allow(struct sock *sk, int type, + struct flowi *fl) +{ +#if 0 + struct dst_entry *dst; + int allow = 0; +#endif + /* Informational messages are not limited. */ + if (type & 0x80) + return 1; + +#if 0 /* not yet, first fix routing COW */ + + /* + * Look up the output route. + * XXX: perhaps the expire for routing entries cloned by + * this lookup should be more aggressive (not longer than timeout). + */ + dst = ip6_route_output(sk, fl, 1); + if (dst->error) + ipv6_statistics.Ip6OutNoRoutes++; + else + allow = xrlim_allow(dst, sysctl_icmpv6_time); + dst_release(dst); + return allow; +#else + return 1; +#endif +} + /* * an inline helper for the "simple" if statement below * checks if parameter problem report is caused by an @@ -214,6 +273,24 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, return; } + /* + * Never answer to a ICMP packet. + */ + if (is_icmp(hdr, (u8*)skb->tail - (u8*)hdr)) { + printk(KERN_DEBUG "icmpv6_send: no reply to icmp\n"); + return; + } + + fl.proto = IPPROTO_ICMPV6; + fl.nl_u.ip6_u.daddr = &hdr->saddr; + fl.nl_u.ip6_u.saddr = saddr; + fl.oif = iif; + fl.uli_u.icmpt.type = type; + fl.uli_u.icmpt.code = code; + + if (!icmpv6_xrlim_allow(sk, type, &fl)) + return; + /* * ok. kick it. checksum will be provided by the * getfrag_t callback. @@ -248,13 +325,6 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, msg.len = len; - fl.proto = IPPROTO_ICMPV6; - fl.nl_u.ip6_u.daddr = &hdr->saddr; - fl.nl_u.ip6_u.saddr = saddr; - fl.oif = iif; - fl.uli_u.icmpt.type = type; - fl.uli_u.icmpt.code = code; - ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, MSG_DONTWAIT); @@ -312,21 +382,6 @@ static void icmpv6_echo_reply(struct sk_buff *skb) dst_release(xchg(&sk->dst_cache, NULL)); } -static __inline__ int ipv6_ext_hdr(u8 nexthdr) -{ - /* - * find out if nexthdr is an extension header or a protocol - */ - return ( (nexthdr == NEXTHDR_HOP) || - (nexthdr == NEXTHDR_ROUTING) || - (nexthdr == NEXTHDR_FRAGMENT) || - (nexthdr == NEXTHDR_ESP) || - (nexthdr == NEXTHDR_AUTH) || - (nexthdr == NEXTHDR_NONE) || - (nexthdr == NEXTHDR_DEST) ); - -} - static void icmpv6_notify(struct sk_buff *skb, int type, int code, unsigned char *buff, int len, struct in6_addr *saddr, struct in6_addr *daddr, @@ -335,39 +390,22 @@ static void icmpv6_notify(struct sk_buff *skb, struct ipv6hdr *hdr = (struct ipv6hdr *) buff; struct inet6_protocol *ipprot; struct sock *sk; - char * pbuff; + struct ipv6_opt_hdr *pb; __u32 info = 0; int hash; u8 nexthdr; - /* now skip over extension headers */ - nexthdr = hdr->nexthdr; - pbuff = (char *) (hdr + 1); + pb = (struct ipv6_opt_hdr *) (hdr + 1); len -= sizeof(struct ipv6hdr); + if (len < 0) + return; - while (ipv6_ext_hdr(nexthdr)) { - int hdrlen; - - if (nexthdr == NEXTHDR_NONE) - return; - - nexthdr = *pbuff; - - /* Header length is size in 8-octet units, not - * including the first 8 octets. - */ - hdrlen = *(pbuff+1); - hdrlen = (hdrlen + 1) << 3; - - if (hdrlen > len) - return; - - /* Now this is right. */ - pbuff += hdrlen; - len -= hdrlen; - } + /* now skip over extension headers */ + pb = ipv6_skip_exthdr(pb, &nexthdr, len); + if (!pb) + return; hash = nexthdr & (MAX_INET_PROTOS - 1); @@ -378,7 +416,7 @@ static void icmpv6_notify(struct sk_buff *skb, continue; if (ipprot->err_handler) - ipprot->err_handler(skb, type, code, pbuff, info, + ipprot->err_handler(skb, type, code, (u8*)pb, info, saddr, daddr, ipprot); return; } @@ -391,7 +429,7 @@ static void icmpv6_notify(struct sk_buff *skb, return; while((sk = raw_v6_lookup(sk, nexthdr, daddr, saddr))) { - rawv6_err(sk, type, code, pbuff, saddr, daddr); + rawv6_err(sk, type, code, (char*)pb, saddr, daddr); sk = sk->next; } } @@ -514,7 +552,7 @@ discard_it: return 0; } -__initfunc(void icmpv6_init(struct net_proto_family *ops)) +__initfunc(int icmpv6_init(struct net_proto_family *ops)) { struct sock *sk; int err; @@ -528,11 +566,11 @@ __initfunc(void icmpv6_init(struct net_proto_family *ops)) icmpv6_socket->state = SS_UNCONNECTED; icmpv6_socket->type=SOCK_RAW; - if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0) + if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0) { printk(KERN_DEBUG "Failed to create the ICMP6 control socket.\n"); - - MOD_DEC_USE_COUNT; + return 1; + } sk = icmpv6_socket->sk; sk->allocation = GFP_ATOMIC; @@ -542,6 +580,16 @@ __initfunc(void icmpv6_init(struct net_proto_family *ops)) ndisc_init(ops); igmp6_init(ops); + return 0; +} + +void icmpv6_cleanup(void) +{ + inet6_del_protocol(&icmpv6_protocol); +#if 0 + ndisc_cleanup(); +#endif + igmp6_cleanup(); } static struct icmp6_err { diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 71ad7e1a0..5f024dddb 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Ian P. Morris <I.P.Morris@soton.ac.uk> * - * $Id: ip6_input.c,v 1.8 1998/02/12 07:43:43 davem Exp $ + * $Id: ip6_input.c,v 1.9 1998/04/30 16:24:24 freitag Exp $ * * Based in linux/net/ipv4/ip_input.c * @@ -70,12 +70,6 @@ struct ipv6_tlvtype { u8 len; }; -struct ipv6_destopt_hdr { - u8 nexthdr; - u8 hdrlen; -}; - - struct tlvtype_proc { u8 type; int (*func) (struct sk_buff *, struct device *dev, __u8 *ptr, diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 9bb2d4d3c..ebd3365cd 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -7,7 +7,7 @@ * * Based on linux/net/ipv4/ip_sockglue.c * - * $Id: ipv6_sockglue.c,v 1.18 1998/03/20 09:12:18 davem Exp $ + * $Id: ipv6_sockglue.c,v 1.19 1998/04/30 16:24:26 freitag Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -242,7 +242,7 @@ void ipv6_cleanup(void) ipv6_sysctl_unregister(); #endif ip6_route_cleanup(); - ndisc_cleanup(); + icmpv6_cleanup(); addrconf_cleanup(); } #endif diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 407698eb1..0e10dcf0b 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: mcast.c,v 1.14 1998/03/20 09:12:18 davem Exp $ + * $Id: mcast.c,v 1.15 1998/04/30 16:24:28 freitag Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -619,8 +619,6 @@ __initfunc(void igmp6_init(struct net_proto_family *ops)) printk(KERN_DEBUG "Failed to create the IGMP6 control socket.\n"); - MOD_DEC_USE_COUNT; - sk = igmp6_socket->sk; sk->allocation = GFP_ATOMIC; sk->num = 256; /* Don't receive any data */ @@ -632,3 +630,9 @@ __initfunc(void igmp6_init(struct net_proto_family *ops)) #endif } +void igmp6_cleanup(void) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("net/igmp6", 0); +#endif +} diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 2e437f2de..e69d90332 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1152,9 +1152,6 @@ __initfunc(void ndisc_init(struct net_proto_family *ops)) printk(KERN_DEBUG "Failed to create the NDISC control socket.\n"); - /* Eeeh... What is it? --ANK */ - MOD_DEC_USE_COUNT; - sk = ndisc_socket->sk; sk->allocation = GFP_ATOMIC; sk->net_pinfo.af_inet6.hop_limit = 255; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 55fecc676..e78cf97a2 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: reassembly.c,v 1.9 1998/02/12 07:43:48 davem Exp $ + * $Id: reassembly.c,v 1.10 1998/04/30 16:24:32 freitag Exp $ * * Based on: net/ipv4/ip_fragment.c * @@ -15,6 +15,11 @@ * 2 of the License, or (at your option) any later version. */ +/* + * Fixes: + * Andi Kleen Make it work with multiple hosts. + * More RFC compliance. + */ #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> @@ -39,8 +44,9 @@ static struct frag_queue ipv6_frag_queue = { &ipv6_frag_queue, &ipv6_frag_queue, - 0, {0}, NULL, NULL, - 0 + 0, {{{0}}}, {{{0}}}, + {0}, NULL, NULL, + 0, 0, NULL }; static void create_frag_entry(struct sk_buff *skb, @@ -72,12 +78,11 @@ static int reasm_frag(struct frag_queue *fq, struct sk_buff **skb, * one it's the kmalloc for a struct ipv6_frag. * Feel free to try other alternatives... */ - reasm_queue(fq, *skb, fhdr); - if ((fhdr->frag_off & __constant_htons(0x0001)) == 0) { fq->last_in = 1; fq->nhptr = nhptr; } + reasm_queue(fq, *skb, fhdr); if (fq->last_in) { if ((nh = reasm_frag_1(fq, skb))) @@ -90,18 +95,27 @@ static int reasm_frag(struct frag_queue *fq, struct sk_buff **skb, return 0; } -int ipv6_reassembly(struct sk_buff **skb, struct device *dev, __u8 *nhptr, +int ipv6_reassembly(struct sk_buff **skbp, struct device *dev, __u8 *nhptr, struct ipv6_options *opt) { - struct frag_hdr *fhdr = (struct frag_hdr *) ((*skb)->h.raw); + struct sk_buff *skb = *skbp; + struct frag_hdr *fhdr = (struct frag_hdr *) (skb->h.raw); struct frag_queue *fq; - + struct ipv6hdr *hdr; + + if ((u8 *)(fhdr+1) > skb->tail) { + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw); + return 0; + } + hdr = skb->nh.ipv6h; for (fq = ipv6_frag_queue.next; fq != &ipv6_frag_queue; fq = fq->next) { - if (fq->id == fhdr->identification) - return reasm_frag(fq, skb, nhptr,fhdr); + if (fq->id == fhdr->identification && + !ipv6_addr_cmp(&hdr->saddr, &fq->saddr) && + !ipv6_addr_cmp(&hdr->daddr, &fq->daddr)) + return reasm_frag(fq, skbp, nhptr,fhdr); } - create_frag_entry(*skb, dev, nhptr, fhdr); + create_frag_entry(skb, dev, nhptr, fhdr); return 0; } @@ -154,6 +168,7 @@ static void create_frag_entry(struct sk_buff *skb, struct device *dev, struct frag_hdr *fhdr) { struct frag_queue *fq; + struct ipv6hdr *hdr; fq = (struct frag_queue *) kmalloc(sizeof(struct frag_queue), GFP_ATOMIC); @@ -167,6 +182,10 @@ static void create_frag_entry(struct sk_buff *skb, struct device *dev, fq->id = fhdr->identification; + hdr = skb->nh.ipv6h; + ipv6_addr_copy(&fq->saddr, &hdr->saddr); + ipv6_addr_copy(&fq->daddr, &hdr->daddr); + fq->dev = dev; /* init_timer has been done by the memset */ @@ -193,14 +212,14 @@ static void create_frag_entry(struct sk_buff *skb, struct device *dev, static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb, - struct frag_hdr *fhdr) + struct frag_hdr *fhdr) { struct ipv6_frag *nfp, *fp, **bptr; nfp = (struct ipv6_frag *) kmalloc(sizeof(struct ipv6_frag), GFP_ATOMIC); - if (nfp == NULL) { + if (nfp == NULL) { kfree_skb(skb); return; } @@ -209,6 +228,10 @@ static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb, nfp->len = (ntohs(skb->nh.ipv6h->payload_len) - ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1))); + if ((u32)nfp->offset + (u32)nfp->len > 65536) { + icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off); + goto err; + } nfp->skb = skb; nfp->fhdr = fhdr; @@ -224,19 +247,37 @@ static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb, } if (fp && fp->offset == nfp->offset) { - if (fp->len != nfp->len) { - /* this cannot happen */ + if (nfp->len != fp->len) { printk(KERN_DEBUG "reasm_queue: dup with wrong len\n"); } /* duplicate. discard it. */ - kfree_skb(skb); - kfree(nfp); - return; + goto err; } *bptr = nfp; nfp->next = fp; + +#ifdef STRICT_RFC + if (fhdr->frag_off & __constant_htons(0x0001)) { + /* Check if the fragment is rounded to 8 bytes. + * Required by the RFC. + */ + if (nfp->len & 0x7) { + printk(KERN_DEBUG "fragment not rounded to 8bytes\n"); + + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, + &skb->nh.ipv6h->payload_len); + goto err; + } + } +#endif + + return; + +err: + kfree(nfp); + kfree_skb(skb); } /* @@ -303,6 +344,8 @@ static int reasm_frag_1(struct frag_queue *fq, struct sk_buff **skb_in) /* * FIXME: If we don't have a checksum we ought to be able * to defragment and checksum in this pass. [AC] + * Note that we don't really know yet whether the protocol + * needs checksums at all. It might still be a good idea. -AK */ for(fp = fq->fragments; fp; ) { struct ipv6_frag *back; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a71c9c0e5..3baa41007 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1379,7 +1379,7 @@ int ipv6_route_ioctl(unsigned int cmd, void *arg) switch(cmd) { case SIOCADDRT: /* Add a route */ case SIOCDELRT: /* Delete a route */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; err = copy_from_user(&rtmsg, arg, sizeof(struct in6_rtmsg)); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 721677fa6..0a4a95c7c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: tcp_ipv6.c,v 1.78 1998/04/16 16:29:22 freitag Exp $ + * $Id: tcp_ipv6.c,v 1.80 1998/05/02 12:47:15 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -123,10 +123,21 @@ static int tcp_v6_verify_bind(struct sock *sk, unsigned short snum) result = 1; } } - if((result == 0) && - (tb == NULL) && - (tcp_bucket_create(snum) == NULL)) - result = 1; + if(result == 0) { + if(tb == NULL) { + if(tcp_bucket_create(snum) == NULL) + result = 1; + } else { + /* It could be pending garbage collection, this + * kills the race and prevents it from disappearing + * out from under us by the time we use it. -DaveM + */ + if(tb->owners == NULL && !(tb->flags & TCPB_FLAG_LOCKED)) { + tb->flags = TCPB_FLAG_LOCKED; + tcp_dec_slow_timer(TCP_SLT_BUCKETGC); + } + } + } go_like_smoke: SOCKHASH_UNLOCK(); return result; @@ -731,7 +742,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, isn = tcp_v6_init_sequence(sk,skb); /* - * There are no SYN attacks on IPv6, yet... + * There are no SYN attacks on IPv6, yet... */ if (BACKLOG(sk) >= BACKLOGMAX(sk)) { printk(KERN_DEBUG "droping syn ack:%d max:%d\n", diff --git a/net/netsyms.c b/net/netsyms.c index 5d380fbb6..52be53033 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -458,7 +458,7 @@ EXPORT_SYMBOL(qdisc_put_rtab); EXPORT_SYMBOL(qdisc_new_estimator); EXPORT_SYMBOL(qdisc_kill_estimator); #endif -#ifdef CONFIG_NET_POLICE +#ifdef CONFIG_NET_CLS_POLICE EXPORT_SYMBOL(tcf_police); EXPORT_SYMBOL(tcf_police_locate); EXPORT_SYMBOL(tcf_police_destroy); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 858ea0e73..f56b660c0 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -691,7 +691,7 @@ static int packet_create(struct socket *sock, int protocol) struct sock *sk; int err; - if (!suser()) + if (!capable(CAP_NET_RAW)) return -EPERM; if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW #ifdef CONFIG_SOCK_PACKET @@ -1089,7 +1089,8 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg err = get_user(pid, (int *) arg); if (err) return err; - if (current->pid != pid && current->pgrp != -pid && !suser()) + if (current->pid != pid && current->pgrp != -pid && + !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; return(0); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 286a2aa68..494b9fa62 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1193,7 +1193,7 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCADDRT: case SIOCDELRT: case SIOCRSCLRRT: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return rose_rt_ioctl(cmd, (void *)arg); case SIOCRSGCAUSE: { diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 30e2c2034..b00d0ab2a 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -371,7 +371,7 @@ int wanrouter_ioctl(struct inode* inode, struct file* file, struct proc_dir_entry* dent; wan_device_t* wandev; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if ((cmd >> 8) != ROUTER_IOCTL) diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 163960409..514f64e1b 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1096,7 +1096,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCADDRT: case SIOCDELRT: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return x25_route_ioctl(cmd, (void *)arg); case SIOCX25GSUBSCRIP: |