]> rtime.felk.cvut.cz Git - linux-lin.git/blob - lin_config/src/sllin_config.c
lin_config: Configuration of sllin frame cache
[linux-lin.git] / lin_config / src / sllin_config.c
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <sys/ioctl.h>
4 #include <sys/uio.h>
5 //#include <net/if.h>
6 #include <linux/if.h>
7 #include <netinet/in.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14
15 #include <netlink/netlink.h>
16 #include <netlink/cache.h>
17 #include <netlink/route/link.h>
18 #include <netlink/socket.h>
19
20 #include <linux/can.h>
21 #include <linux/can/bcm.h>
22
23 #include "lin_config.h"
24 #include "linux/lin_bus.h"
25
26 #define SLLIN_LDISC                                     25
27 struct bcm_msg {
28         struct bcm_msg_head msg_head;
29         struct can_frame frame;
30 };
31
32 struct sllin_connection {
33         int bcm_sock; // FIXME is necessary??
34         int can_sock;
35         char iface[IFNAMSIZ+1];
36 };
37
38 void sllin_ms_to_timeval(int ms, struct timeval *tv)
39 {
40         tv->tv_sec = (int) ms/1000;
41         tv->tv_usec = (ms % 1000) * 1000;
42 }
43
44 int sllin_interface_up(struct linc_lin_state *linc_lin_state,
45                         struct sllin_connection *sllin_connection)
46 {
47         struct nl_sock *s;
48         struct rtnl_link *request;
49         struct nl_cache *cache;
50         struct rtnl_link *link;
51         int ret;
52
53         // Allocate and initialize a new netlink socket
54         s = nl_socket_alloc();
55
56         // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example.
57         nl_connect(s, NETLINK_ROUTE);
58
59         // The first step is to retrieve a list of all available interfaces within
60         // the kernel and put them into a cache.
61         ret = rtnl_link_alloc_cache(s, AF_UNSPEC, &cache);
62         // FIXME errorhandling
63
64         // In a second step, a specific link may be looked up by either interface
65         // index or interface name.
66         link = rtnl_link_get_by_name(cache, sllin_connection->iface);
67
68         // In order to change any attributes of an existing link, we must allocate
69         // a new link to hold the change requests:
70         request = rtnl_link_alloc();
71
72         // We can also shut an interface down administratively
73         //rtnl_link_unset_flags(request, rtnl_link_str2flags("up"));
74         rtnl_link_set_flags(request, rtnl_link_str2flags("up"));
75
76         // Two ways exist to commit this change request, the first one is to
77         // build the required netlink message and send it out in one single
78         // step:
79         rtnl_link_change(s, link, request, 0);
80
81         // An alternative way is to build the netlink message and send it
82         // out yourself using nl_send_auto_complete()
83         // struct nl_msg *msg = rtnl_link_build_change_request(old, request);
84         // nl_send_auto_complete(nl_handle, nlmsg_hdr(msg));
85         // nlmsg_free(msg);
86
87         // After successful usage, the object must be given back to the cache
88         rtnl_link_put(link);
89         nl_socket_free(s);
90
91         return 0;
92 }
93
94 int sllin_cache_config(struct linc_lin_state *linc_lin_state,
95                         struct sllin_connection *sllin_connection)
96 {
97         int i;
98         struct ifreq ifr;
99         struct sockaddr_can addr;
100         struct can_frame frame;
101         int s;
102         int ret;
103
104         /* Create the socket */
105         s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
106         if (s < 0) {
107                 perror("socket()");
108                 return -1;
109         }
110
111         /* Locate the interface you wish to use */
112         strcpy(ifr.ifr_name, sllin_connection->iface);
113         ioctl(s, SIOCGIFINDEX, &ifr); /* ifr.ifr_ifindex gets filled
114                                        * with that device's index */
115
116         /* Select that CAN interface, and bind the socket to it. */
117         addr.can_family = AF_CAN;
118         addr.can_ifindex = ifr.ifr_ifindex;
119         ret = bind(s, (struct sockaddr*)&addr, sizeof(addr));
120         if (ret < 0) {
121                 perror("bind()");
122                 return -1;
123         }
124
125         for (i = 0; i < 0x3F; i++) {
126                 if (linc_lin_state->frame_entry[i].status == 1) { /* Is active */
127                         frame.can_dlc = linc_lin_state->frame_entry[i].data_len;
128                         frame.can_id = i; /* LIN ID */
129                         frame.data[0] = linc_lin_state->frame_entry[i].data[0]; /* Data */
130                         frame.data[1] = linc_lin_state->frame_entry[i].data[1]; /* Data */
131                         frame.data[2] = linc_lin_state->frame_entry[i].data[2]; /* Data */
132                         frame.data[3] = linc_lin_state->frame_entry[i].data[3]; /* Data */
133                         frame.data[4] = linc_lin_state->frame_entry[i].data[4]; /* Data */
134                         frame.data[5] = linc_lin_state->frame_entry[i].data[5]; /* Data */
135                         frame.data[6] = linc_lin_state->frame_entry[i].data[6]; /* Data */
136                         frame.data[7] = linc_lin_state->frame_entry[i].data[7]; /* Data */
137
138                         frame.can_id |= LIN_CTRL_FRAME | LIN_CACHE_RESPONSE;
139                         ret = write(s, &frame, sizeof(frame));
140                         printf("configuring frame cache; ret = %d\n", ret);
141                         //if (ret ...)
142                         //read_response(tty);
143                 }
144         }
145
146         close(s);
147         return 0;
148 }
149
150 int sllin_bcm_config(struct linc_lin_state *linc_lin_state,
151                         struct sllin_connection *sllin_connection)
152 {
153         struct sockaddr_can caddr;
154         struct ifreq ifr;
155         struct bcm_msg msg;
156         int s;
157         int ret;
158         int i;
159
160         s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);
161         if (s < 0) {
162                 perror("socket(): bcmsocket");
163                 return -1;
164         }
165
166         strcpy(ifr.ifr_name, sllin_connection->iface);
167         ioctl(s, SIOCGIFINDEX, &ifr);
168
169         memset(&caddr, 0, sizeof(caddr));
170         caddr.can_family = AF_CAN;
171         caddr.can_ifindex = ifr.ifr_ifindex;
172
173 //      ret = bind(s, (struct sockaddr*)&caddr, sizeof(caddr));
174 //      if (ret < 0) {
175 //              perror("bind()");
176 //              return -1;
177 //      }
178 //
179 //      sllin_connection->bcm_sock = s;
180
181         ret = connect(s, (struct sockaddr *)&caddr, sizeof(caddr));
182         if (ret < 0) {
183                 perror("connect()");
184                 return -1;
185         }
186
187         for (i = 0; i < linc_lin_state->scheduler_entries_cnt; i++) {
188                 struct timeval time;
189                 memset(&msg, 0, sizeof(msg));
190
191                 msg.msg_head.nframes = 1;
192                 msg.msg_head.opcode = TX_SETUP;
193                 msg.msg_head.flags |= SETTIMER | STARTTIMER;
194                 sllin_ms_to_timeval(
195                         linc_lin_state->scheduler_entry[i].interval_ms, &time);
196                 msg.msg_head.ival2.tv_sec = time.tv_sec;
197                 msg.msg_head.ival2.tv_usec = time.tv_usec;
198                 msg.msg_head.can_id = (
199                         linc_lin_state->scheduler_entry[i].lin_id | CAN_RTR_FLAG);
200                 msg.frame.can_dlc = 0;
201                 msg.frame.can_id = msg.msg_head.can_id;
202
203                 //printf("tv_sec = %i, tv_usec = %i\n", time.tv_sec, time.tv_usec);
204
205                 sendto(s, &msg, sizeof(msg), 0,
206                         (struct sockaddr*)&caddr, sizeof(caddr));
207                 //read_response(s); // FIXME
208         }
209
210         /* Do not close "s" to make BCM configuration running */
211
212         printf("Configuration finished\n");
213         return 0;
214 }
215
216 int sllin_config(struct linc_lin_state *linc_lin_state)
217 {
218         int tty;
219         int ldisc = SLLIN_LDISC;
220         int ret;
221         struct sllin_connection sllin_connection;
222
223         tty = open(linc_lin_state->dev, O_WRONLY | O_NOCTTY);
224         if (tty < 0) {
225                 perror("open()");
226                 return -1;
227         }
228
229         /* Set sllin line discipline on given tty */
230         if (linc_lin_state->flags & SLLIN_ATTACH_fl) {
231                 ret = ioctl(tty, TIOCSETD, &ldisc);
232                 if (ret < 0) {
233                         perror("ioctl TIOCSETD");
234                         return -1;
235                 }
236
237                 /* Retrieve the name of the created CAN netdevice */
238                 ret = ioctl(tty, SIOCGIFNAME, sllin_connection.iface);
239                 if (ret < 0) {
240                         perror("ioctl SIOCGIFNAME");
241                         return -1;
242                 }
243
244                 printf("Attached tty %s to netdevice %s\n",
245                         linc_lin_state->dev, sllin_connection.iface);
246         }
247
248         if (linc_lin_state->flags & SLLIN_DETACH_fl) {
249                 ldisc = N_TTY;
250                 ret = ioctl(tty, TIOCSETD, &ldisc);
251                 if (ret < 0) {
252                         perror("ioctl");
253                         return -1;
254                 }
255
256                 printf("Detached sllin line discipline from %s\n",
257                         linc_lin_state->dev);
258
259                 close(tty);
260                 return LIN_EXIT_OK;
261         }
262
263         ret = sllin_bcm_config(linc_lin_state, &sllin_connection);
264         if (ret < 0)
265                 return ret;
266
267         ret = sllin_interface_up(linc_lin_state, &sllin_connection);
268         if (ret < 0)
269                 return ret;
270
271         ret = sllin_cache_config(linc_lin_state, &sllin_connection);
272
273         /* !!! Do not close "tty" to enable newly
274            configured tty line discipline */
275
276         return ret;
277 }
278