Newer
Older
break;
last_perm = lh;
}
answer = NULL;
}
if (answer)
goto out_permanent;
/* Add the new entry after the last permanent entry if any, so that
* the new entry does not override a permanent entry when matched with
* a wild-card protocol. But it is allowed to override any existing
* non-permanent entry. This means that when we remove this entry, the
* system automatically returns to the old behavior.
*/
list_add_rcu(&p->list, last_perm);
out:
spin_unlock_bh(&inetsw_lock);
return;
out_permanent:
printk(KERN_ERR "Attempt to override permanent protocol %d.\n",
protocol);
goto out;
out_illegal:
printk(KERN_ERR
"Ignoring attempt to register invalid socket type %d.\n",
p->type);
goto out;
}
void inet_unregister_protosw(struct inet_protosw *p)
{
if (INET_PROTOSW_PERMANENT & p->flags) {
printk(KERN_ERR
"Attempt to unregister permanent protocol %d.\n",
p->protocol);
} else {
spin_lock_bh(&inetsw_lock);
list_del_rcu(&p->list);
spin_unlock_bh(&inetsw_lock);
synchronize_net();
}
}
/*
* Shall we try to damage output packets if routing dev changes?
*/
int sysctl_ip_dynaddr __read_mostly;
static int inet_sk_reselect_saddr(struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
int err;
struct rtable *rt;
__be32 old_saddr = inet->saddr;
__be32 new_saddr;
__be32 daddr = inet->daddr;
if (inet->opt && inet->opt->srr)
daddr = inet->opt->faddr;
/* Query new route. */
err = ip_route_connect(&rt, daddr, 0,
RT_CONN_FLAGS(sk),
sk->sk_bound_dev_if,
sk->sk_protocol,
inet->sport, inet->dport, sk, 0);
if (err)
return err;
sk_setup_caps(sk, &rt->u.dst);
new_saddr = rt->rt_src;
if (new_saddr == old_saddr)
return 0;
if (sysctl_ip_dynaddr > 1) {
printk(KERN_INFO "%s(): shifting inet->saddr from %pI4 to %pI4\n",
__func__, &old_saddr, &new_saddr);
}
inet->saddr = inet->rcv_saddr = new_saddr;
/*
* XXX The only one ugly spot where we need to
* XXX really change the sockets identity after
* XXX it has entered the hashes. -DaveM
*
* Besides that, it does not check for connection
* uniqueness. Wait for troubles.
*/
__sk_prot_rehash(sk);
return 0;
}
int inet_sk_rebuild_header(struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
int err;
/* Route is OK, nothing to do. */
if (rt)
return 0;
/* Reroute. */
daddr = inet->daddr;
if (inet->opt && inet->opt->srr)
daddr = inet->opt->faddr;
{
struct flowi fl = {
.oif = sk->sk_bound_dev_if,
.nl_u = {
.ip4_u = {
.daddr = daddr,
.saddr = inet->saddr,
.tos = RT_CONN_FLAGS(sk),
},
},
.proto = sk->sk_protocol,

Balazs Scheidler
committed
.flags = inet_sk_flowi_flags(sk),
.uli_u = {
.ports = {
.sport = inet->sport,
.dport = inet->dport,
},
},
};
err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0);
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
}
if (!err)
sk_setup_caps(sk, &rt->u.dst);
else {
/* Routing failed... */
sk->sk_route_caps = 0;
/*
* Other protocols have to map its equivalent state to TCP_SYN_SENT.
* DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme
*/
if (!sysctl_ip_dynaddr ||
sk->sk_state != TCP_SYN_SENT ||
(sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
(err = inet_sk_reselect_saddr(sk)) != 0)
sk->sk_err_soft = -err;
}
return err;
}
EXPORT_SYMBOL(inet_sk_rebuild_header);
static int inet_gso_send_check(struct sk_buff *skb)
{
struct iphdr *iph;
struct net_protocol *ops;
int proto;
int ihl;
int err = -EINVAL;
if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
goto out;
iph = ip_hdr(skb);
ihl = iph->ihl * 4;
if (ihl < sizeof(*iph))
goto out;
if (unlikely(!pskb_may_pull(skb, ihl)))
goto out;
__skb_pull(skb, ihl);
skb_reset_transport_header(skb);
iph = ip_hdr(skb);
proto = iph->protocol & (MAX_INET_PROTOS - 1);
err = -EPROTONOSUPPORT;
rcu_read_lock();
ops = rcu_dereference(inet_protos[proto]);
if (likely(ops && ops->gso_send_check))
err = ops->gso_send_check(skb);
rcu_read_unlock();
out:
return err;
}
static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
struct iphdr *iph;
struct net_protocol *ops;
int proto;
int ihl;
int id;
unsigned int offset = 0;
if (!(features & NETIF_F_V4_CSUM))
features &= ~NETIF_F_SG;
if (unlikely(skb_shinfo(skb)->gso_type &
~(SKB_GSO_TCPV4 |
SKB_GSO_UDP |
SKB_GSO_DODGY |
SKB_GSO_TCP_ECN |
0)))
goto out;
if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
iph = ip_hdr(skb);
ihl = iph->ihl * 4;
if (ihl < sizeof(*iph))
goto out;
if (unlikely(!pskb_may_pull(skb, ihl)))
__skb_pull(skb, ihl);
skb_reset_transport_header(skb);
iph = ip_hdr(skb);
id = ntohs(iph->id);
proto = iph->protocol & (MAX_INET_PROTOS - 1);
segs = ERR_PTR(-EPROTONOSUPPORT);
rcu_read_lock();
ops = rcu_dereference(inet_protos[proto]);
if (likely(ops && ops->gso_segment))
segs = ops->gso_segment(skb, features);
if (!segs || IS_ERR(segs))
iph = ip_hdr(skb);
if (proto == IPPROTO_UDP) {
iph->id = htons(id);
iph->frag_off = htons(offset >> 3);
if (skb->next != NULL)
iph->frag_off |= htons(IP_MF);
offset += (skb->len - skb->mac_len - iph->ihl * 4);
} else
iph->id = htons(id++);
iph->tot_len = htons(skb->len - skb->mac_len);
iph->check = 0;
iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
} while ((skb = skb->next));
out:
return segs;
}
static struct sk_buff **inet_gro_receive(struct sk_buff **head,
struct sk_buff *skb)
{
struct net_protocol *ops;
struct sk_buff **pp = NULL;
struct sk_buff *p;
struct iphdr *iph;
unsigned int hlen;
unsigned int off;
off = skb_gro_offset(skb);
hlen = off + sizeof(*iph);
iph = skb_gro_header_fast(skb, off);
if (skb_gro_header_hard(skb, hlen)) {
iph = skb_gro_header_slow(skb, hlen, off);
if (unlikely(!iph))
goto out;
}
proto = iph->protocol & (MAX_INET_PROTOS - 1);
rcu_read_lock();
ops = rcu_dereference(inet_protos[proto]);
if (!ops || !ops->gro_receive)
goto out_unlock;
goto out_unlock;
if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
goto out_unlock;
id = ntohl(*(u32 *)&iph->id);
flush = (u16)((ntohl(*(u32 *)iph) ^ skb_gro_len(skb)) | (id ^ IP_DF));
id >>= 16;
for (p = *head; p; p = p->next) {
struct iphdr *iph2;
if (!NAPI_GRO_CB(p)->same_flow)
continue;
iph2 = ip_hdr(p);
if ((iph->protocol ^ iph2->protocol) |
(iph->tos ^ iph2->tos) |
(iph->saddr ^ iph2->saddr) |
(iph->daddr ^ iph2->daddr)) {
NAPI_GRO_CB(p)->same_flow = 0;
continue;
}
/* All fields must match except length and checksum. */
NAPI_GRO_CB(p)->flush |=
(iph->ttl ^ iph2->ttl) |
((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id);
NAPI_GRO_CB(p)->flush |= flush;
}
NAPI_GRO_CB(skb)->flush |= flush;
skb_gro_pull(skb, sizeof(*iph));
skb_set_transport_header(skb, skb_gro_offset(skb));
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
pp = ops->gro_receive(head, skb);
out_unlock:
rcu_read_unlock();
out:
NAPI_GRO_CB(skb)->flush |= flush;
return pp;
}
static int inet_gro_complete(struct sk_buff *skb)
{
struct net_protocol *ops;
struct iphdr *iph = ip_hdr(skb);
int proto = iph->protocol & (MAX_INET_PROTOS - 1);
int err = -ENOSYS;
__be16 newlen = htons(skb->len - skb_network_offset(skb));
csum_replace2(&iph->check, iph->tot_len, newlen);
iph->tot_len = newlen;
rcu_read_lock();
ops = rcu_dereference(inet_protos[proto]);
if (WARN_ON(!ops || !ops->gro_complete))
goto out_unlock;
err = ops->gro_complete(skb);
out_unlock:
rcu_read_unlock();
return err;
}
int inet_ctl_sock_create(struct sock **sk, unsigned short family,
unsigned short type, unsigned char protocol,
struct net *net)
struct socket *sock;
int rc = sock_create_kern(family, type, protocol, &sock);
if (rc == 0) {
*sk = sock->sk;
(*sk)->sk_allocation = GFP_ATOMIC;
/*
* Unhash it so that IP input processing does not even see it,
* we do not wish this socket to see incoming packets.
*/
(*sk)->sk_prot->unhash(*sk);
sk_change_net(*sk, net);
}
return rc;
}
EXPORT_SYMBOL_GPL(inet_ctl_sock_create);
unsigned long snmp_fold_field(void *mib[], int offt)
{
unsigned long res = 0;
int i;
for_each_possible_cpu(i) {
res += *(((unsigned long *) per_cpu_ptr(mib[0], i)) + offt);
res += *(((unsigned long *) per_cpu_ptr(mib[1], i)) + offt);
}
return res;
}
EXPORT_SYMBOL_GPL(snmp_fold_field);
int snmp_mib_init(void *ptr[2], size_t mibsize)
ptr[0] = __alloc_percpu(mibsize, __alignof__(unsigned long long));
ptr[1] = __alloc_percpu(mibsize, __alignof__(unsigned long long));
if (!ptr[1])
goto err1;
return 0;
err1:
free_percpu(ptr[0]);
ptr[0] = NULL;
err0:
return -ENOMEM;
}
EXPORT_SYMBOL_GPL(snmp_mib_init);
void snmp_mib_free(void *ptr[2])
{
BUG_ON(ptr == NULL);
free_percpu(ptr[0]);
free_percpu(ptr[1]);
ptr[0] = ptr[1] = NULL;
}
EXPORT_SYMBOL_GPL(snmp_mib_free);
#ifdef CONFIG_IP_MULTICAST
static struct net_protocol igmp_protocol = {
.handler = igmp_rcv,
};
#endif
static struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.gso_send_check = tcp_v4_gso_send_check,
.gro_receive = tcp4_gro_receive,
.gro_complete = tcp4_gro_complete,
};
static struct net_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
.gso_send_check = udp4_ufo_send_check,
.gso_segment = udp4_ufo_fragment,
};
static struct net_protocol icmp_protocol = {
.handler = icmp_rcv,
static __net_init int ipv4_mib_init_net(struct net *net)
{
if (snmp_mib_init((void **)net->mib.tcp_statistics,
sizeof(struct tcp_mib)) < 0)
goto err_tcp_mib;
if (snmp_mib_init((void **)net->mib.ip_statistics,
sizeof(struct ipstats_mib)) < 0)
goto err_ip_mib;
if (snmp_mib_init((void **)net->mib.net_statistics,
sizeof(struct linux_mib)) < 0)
goto err_net_mib;
if (snmp_mib_init((void **)net->mib.udp_statistics,
sizeof(struct udp_mib)) < 0)
goto err_udp_mib;
if (snmp_mib_init((void **)net->mib.udplite_statistics,
sizeof(struct udp_mib)) < 0)
goto err_udplite_mib;
if (snmp_mib_init((void **)net->mib.icmp_statistics,
sizeof(struct icmp_mib)) < 0)
goto err_icmp_mib;
if (snmp_mib_init((void **)net->mib.icmpmsg_statistics,
sizeof(struct icmpmsg_mib)) < 0)
goto err_icmpmsg_mib;
err_icmpmsg_mib:
snmp_mib_free((void **)net->mib.icmp_statistics);
err_icmp_mib:
snmp_mib_free((void **)net->mib.udplite_statistics);
err_udplite_mib:
snmp_mib_free((void **)net->mib.udp_statistics);
err_udp_mib:
snmp_mib_free((void **)net->mib.net_statistics);
err_net_mib:
snmp_mib_free((void **)net->mib.ip_statistics);
err_ip_mib:
snmp_mib_free((void **)net->mib.tcp_statistics);
err_tcp_mib:
return -ENOMEM;
}
static __net_exit void ipv4_mib_exit_net(struct net *net)
{
snmp_mib_free((void **)net->mib.icmpmsg_statistics);
snmp_mib_free((void **)net->mib.icmp_statistics);
snmp_mib_free((void **)net->mib.udplite_statistics);
snmp_mib_free((void **)net->mib.udp_statistics);
snmp_mib_free((void **)net->mib.net_statistics);
snmp_mib_free((void **)net->mib.ip_statistics);
snmp_mib_free((void **)net->mib.tcp_statistics);
}
static __net_initdata struct pernet_operations ipv4_mib_ops = {
.init = ipv4_mib_init_net,
.exit = ipv4_mib_exit_net,
};
return register_pernet_subsys(&ipv4_mib_ops);
/*
* IP protocol layer initialiser
*/
static struct packet_type ip_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_IP),
.func = ip_rcv,
.gso_send_check = inet_gso_send_check,
.gro_receive = inet_gro_receive,
.gro_complete = inet_gro_complete,
static int __init inet_init(void)
{
struct sk_buff *dummy_skb;
struct inet_protosw *q;
struct list_head *r;
int rc = -EINVAL;
BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb));
rc = proto_register(&tcp_prot, 1);
if (rc)
goto out;
rc = proto_register(&udp_prot, 1);
if (rc)
goto out_unregister_tcp_proto;
rc = proto_register(&raw_prot, 1);
if (rc)
goto out_unregister_udp_proto;
/*
* Tell SOCKET that we are alive...
(void)sock_register(&inet_family_ops);
#ifdef CONFIG_SYSCTL
ip_static_sysctl_init();
#endif
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
/*
* Add all the base protocols.
*/
if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
#ifdef CONFIG_IP_MULTICAST
if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");
#endif
/* Register the socket-side information for inet_create. */
for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
INIT_LIST_HEAD(r);
for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
inet_register_protosw(q);
/*
* Set the ARP module up
*/
arp_init();
/*
* Set the IP module up
*/
tcp_v4_init();
/* Setup TCP slab cache for open requests. */
tcp_init();
/* Setup UDP memory threshold */
udp_init();
/* Add UDP-Lite (RFC 3828) */
udplite4_register();
if (icmp_init() < 0)
panic("Failed to create the ICMP control socket.\n");
/*
* Initialise the multicast router
*/
#if defined(CONFIG_IP_MROUTE)
if (ip_mr_init())
printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n");
printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");
dev_add_pack(&ip_packet_type);
rc = 0;
out:
return rc;
out_unregister_udp_proto:
proto_unregister(&udp_prot);
out_unregister_tcp_proto:
proto_unregister(&tcp_prot);
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
/* ------------------------------------------------------------------------ */
#ifdef CONFIG_PROC_FS
static int __init ipv4_proc_init(void)
{
int rc = 0;
if (raw_proc_init())
goto out_raw;
if (tcp4_proc_init())
goto out_tcp;
if (udp4_proc_init())
goto out_udp;
if (ip_misc_proc_init())
goto out_misc;
out:
return rc;
out_misc:
udp4_proc_exit();
out_udp:
tcp4_proc_exit();
out_tcp:
raw_proc_exit();
out_raw:
rc = -ENOMEM;
goto out;
}
#else /* CONFIG_PROC_FS */
static int __init ipv4_proc_init(void)
{
return 0;
}
#endif /* CONFIG_PROC_FS */
MODULE_ALIAS_NETPROTO(PF_INET);