Newer
Older
struct ip_tunnel *t = netdev_priv(dev);
struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
p[0] = t->parms.o_flags;
p[1] = htons(type);
/*
* Set the source hardware address.
if (saddr)
memcpy(&iph->saddr, saddr, 4);
if (daddr) {
memcpy(&iph->daddr, daddr, 4);
return t->hlen;
}
if (iph->daddr && !ipv4_is_multicast(iph->daddr))
static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
struct iphdr *iph = (struct iphdr*) skb_mac_header(skb);
memcpy(haddr, &iph->saddr, 4);
return 4;
}
static const struct header_ops ipgre_header_ops = {
.create = ipgre_header,
#ifdef CONFIG_NET_IPGRE_BROADCAST
struct ip_tunnel *t = netdev_priv(dev);
if (ipv4_is_multicast(t->parms.iph.daddr)) {
struct flowi fl = { .oif = t->parms.link,
.nl_u = { .ip4_u =
{ .daddr = t->parms.iph.daddr,
.saddr = t->parms.iph.saddr,
.tos = RT_TOS(t->parms.iph.tos) } },
.proto = IPPROTO_GRE };
struct rtable *rt;
if (ip_route_output_key(dev_net(dev), &rt, &fl))
return -EADDRNOTAVAIL;
dev = rt->u.dst.dev;
ip_rt_put(rt);
if (__in_dev_get_rtnl(dev) == NULL)
ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
}
return 0;
}
static int ipgre_close(struct net_device *dev)
{
struct ip_tunnel *t = netdev_priv(dev);
if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
struct in_device *in_dev;
in_dev = inetdev_by_index(dev_net(dev), t->mlink);
if (in_dev) {
ip_mc_dec_group(in_dev, t->parms.iph.daddr);
in_dev_put(in_dev);
}
}
return 0;
}
#endif
static void ipgre_tunnel_setup(struct net_device *dev)
{
dev->uninit = ipgre_tunnel_uninit;
dev->destructor = free_netdev;
dev->hard_start_xmit = ipgre_tunnel_xmit;
dev->do_ioctl = ipgre_tunnel_ioctl;
dev->change_mtu = ipgre_tunnel_change_mtu;
dev->type = ARPHRD_IPGRE;
dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
dev->flags = IFF_NOARP;
dev->iflink = 0;
dev->addr_len = 4;
dev->features |= NETIF_F_NETNS_LOCAL;
}
static int ipgre_tunnel_init(struct net_device *dev)
{
struct ip_tunnel *tunnel;
struct iphdr *iph;
tunnel = netdev_priv(dev);
iph = &tunnel->parms.iph;
tunnel->dev = dev;
strcpy(tunnel->parms.name, dev->name);
memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
ipgre_tunnel_bind_dev(dev);
if (iph->daddr) {
#ifdef CONFIG_NET_IPGRE_BROADCAST
if (!iph->saddr)
return -EINVAL;
dev->flags = IFF_BROADCAST;
dev->header_ops = &ipgre_header_ops;
dev->open = ipgre_open;
dev->stop = ipgre_close;
}
#endif
dev->header_ops = &ipgre_header_ops;
static int ipgre_fb_tunnel_init(struct net_device *dev)
struct ip_tunnel *tunnel = netdev_priv(dev);
struct ipgre_net *ign = net_generic(dev_net(dev), ipgre_net_id);
tunnel->dev = dev;
strcpy(tunnel->parms.name, dev->name);
iph->version = 4;
iph->protocol = IPPROTO_GRE;
iph->ihl = 5;
tunnel->hlen = sizeof(struct iphdr) + 4;
dev_hold(dev);
return 0;
}
static struct net_protocol ipgre_protocol = {
.handler = ipgre_rcv,
.err_handler = ipgre_err,
static void ipgre_destroy_tunnels(struct ipgre_net *ign)
{
int prio;
for (prio = 0; prio < 4; prio++) {
int h;
for (h = 0; h < HASH_SIZE; h++) {
struct ip_tunnel *t;
while ((t = ign->tunnels[prio][h]) != NULL)
unregister_netdevice(t->dev);
}
}
}
static int ipgre_init_net(struct net *net)
{
int err;
struct ipgre_net *ign;
err = -ENOMEM;
ign = kzalloc(sizeof(struct ipgre_net), GFP_KERNEL);
if (ign == NULL)
goto err_alloc;
err = net_assign_generic(net, ipgre_net_id, ign);
if (err < 0)
goto err_assign;
ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
ipgre_tunnel_setup);
if (!ign->fb_tunnel_dev) {
err = -ENOMEM;
goto err_alloc_dev;
}
ign->fb_tunnel_dev->init = ipgre_fb_tunnel_init;
dev_net_set(ign->fb_tunnel_dev, net);
if ((err = register_netdev(ign->fb_tunnel_dev)))
goto err_reg_dev;
return 0;
err_reg_dev:
free_netdev(ign->fb_tunnel_dev);
err_alloc_dev:
/* nothing */
err_assign:
kfree(ign);
err_alloc:
return err;
}
static void ipgre_exit_net(struct net *net)
{
struct ipgre_net *ign;
ign = net_generic(net, ipgre_net_id);
kfree(ign);
}
static struct pernet_operations ipgre_net_ops = {
.init = ipgre_init_net,
.exit = ipgre_exit_net,
};
/*
* And now the modules code and kernel interface.
*/
static int __init ipgre_init(void)
{
int err;
printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
if (inet_add_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) {
printk(KERN_INFO "ipgre init: can't add protocol\n");
return -EAGAIN;
}
err = register_pernet_gen_device(&ipgre_net_id, &ipgre_net_ops);
if (err < 0)
inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
static void __exit ipgre_fini(void)
{
if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
printk(KERN_INFO "ipgre close: can't remove protocol\n");
unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops);
}
module_init(ipgre_init);
module_exit(ipgre_fini);
MODULE_LICENSE("GPL");