summaryrefslogtreecommitdiffstats
path: root/net/ax25/ax25_netlink.c
blob: 73e25e2340bf7fefa2937d05af64d62c2188f1c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 * ax25_netlink.c: NETLINK interface for NEW-AX.25
 *
 * Authors:        Jens David (DG1KJD), Matthias Welwarsky (DG2FEF), Jonathan (
 *                 Alan Cox (GW4PTS), Joerg (DL1BKE), et al
 *
 * Comment:        It is intended to develop a new AX.25 routing daemon using t
 *                 method to communicate with the kernel part. Recent developme
 *                 Linux' realtime abilities, however, suggest removing AX.25 c
 *                 from kernel space.
 *
 * Changelog:
 *
 * License:       This module is free software; you can redistribute it and/or
 *                modify it under the terms of the GNU General Public License
 *                as published by the Free Software Foundation; either version
 *                2 of the License, or (at your option) any later version.
*/

#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/ax25.h>
#include <net/sock.h>
#include <net/ax25.h>

#include "ax25_netlink.h"
#include "ax25_route.h"

static struct sock *axrtnl;

static void ax25_netlink_rcv(struct sock *sk, int len)
{
        struct ax25_nlmsg *nlmsg;
	struct sk_buff *skb;
	struct net_device *dev;

	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
		if (skb->len < sizeof(struct ax25_nlmsg)) {
			kfree_skb(skb);
			break;
		}
		nlmsg = (struct ax25_nlmsg *)skb->data;

		switch (nlmsg->msg_type) {
		case AX25_MSG_SETRT:
			if ((dev = dev_get(nlmsg->msg.pathmsg.port_name)) != NULL
			    && nlmsg->msg.pathmsg.path.dcount <= AX25_MAX_DIGIS)
				ax25_add_route(&nlmsg->msg.pathmsg.path, dev);
			break;

		case AX25_MSG_DELRT:
			if ((dev = dev_get(nlmsg->msg.pathmsg.port_name)) != NULL)
				ax25_del_route(&nlmsg->msg.pathmsg.path.addr);
			break;

		case AX25_MSG_OPTRT:
			if ((dev = dev_get(nlmsg->msg.pathmsg.port_name)) != NULL
			    && nlmsg->msg.pathmsg.path.dcount <= AX25_MAX_DIGIS)
			{
				ax25_add_route(&nlmsg->msg.pathmsg.path, dev);
				ax25_ipopt_route(&nlmsg->msg.pathmsg.path.addr, nlmsg->msg.pathmsg.mode);
			}
		}
		kfree_skb(skb);
	}
}

void ax25_nlpost_route(ax25_pktinfo *pkt, struct net_device *dev)
{
	struct ax25_nlmsg *nlmsg;
	struct sk_buff *skb;

	skb = alloc_skb(sizeof(struct ax25_nlmsg), GFP_ATOMIC);
	if (!skb)
		return;
	nlmsg = (struct ax25_nlmsg *)skb_put(skb, sizeof(struct ax25_nlmsg));

	nlmsg->msg_type = AX25_MSG_RTINFO;
	strncpy(nlmsg->msg.rtmsg.port_name, dev->name, sizeof(nlmsg->msg.rtmsg.port_name));
	nlmsg->msg.rtmsg.addr = pkt->addr;
	netlink_broadcast(axrtnl, skb, 0, ~0, GFP_KERNEL);
}

void ax25_nlpost_armsg(unsigned int ip_addr, ax25_address *ax_addr, struct net_device *dev)
{
	struct ax25_nlmsg *nlmsg;
	struct sk_buff *skb;

	skb = alloc_skb(sizeof(struct ax25_nlmsg), GFP_ATOMIC);
	if (!skb)
		return;
	nlmsg = (struct ax25_nlmsg *)skb_put(skb, sizeof(struct ax25_nlmsg));

	nlmsg->msg_type = AX25_MSG_ARINFO;
	strncpy(nlmsg->msg.armsg.port_name, dev->name, sizeof(nlmsg->msg.armsg.port_name));
	nlmsg->msg.armsg.ip_addr = ip_addr;
	nlmsg->msg.armsg.ax_addr = *ax_addr;

	netlink_broadcast(axrtnl, skb, 0, ~0, GFP_KERNEL);
}

void ax25_netlink_init(void)
{
	axrtnl = netlink_kernel_create(NETLINK_AX25, ax25_netlink_rcv);
}

void ax25_netlink_cleanup(void)
{
	sock_release(axrtnl->socket);
}