http://gimel.esc.cam.ac.uk/james/rpld/src/rpld-1.7.tar.gz
[rpld.git] / llc-linux.c
1 /*************************************************
2 *     rpld - an IBM style RIPL server            *
3 *************************************************/
4
5 /* Copyright (c) 2000, James McKenzie.
6  *                      All rights reserved
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENCE file which can be found at the top level of
10  * the rpld distribution.
11  *
12  * IBM is a trademark of IBM corp.
13  *
14  */
15
16 static char rcsid[] =
17   "$Id: llc-linux.c,v 1.9 2000/09/26 04:06:07 root Exp root $";
18
19 /*
20  * $Log: llc-linux.c,v $
21  * Revision 1.9  2000/09/26 04:06:07  root
22  * #
23  *
24  * Revision 1.8  2000/09/26 03:48:23  root
25  * #
26  *
27  * Revision 1.7  2000/09/26 03:45:52  root
28  * #
29  *
30  * Revision 1.6  2000/09/26 02:32:46  root
31  * #
32  *
33  * Revision 1.5  2000/09/26 01:42:24  root
34  * #
35  *
36  * Revision 1.4  2000/09/26 01:41:22  root
37  * #
38  *
39  * Revision 1.3  2000/09/26 01:41:08  root
40  * #
41  *
42  * Revision 1.2  2000/09/26 01:39:17  root
43  * #
44  *
45  * Revision 1.1  2000/09/26 01:03:19  root
46  * #
47  *
48  *
49  */
50
51
52 #include "project.h"
53 #include "llc.h"
54
55 #undef __GLIBC__
56 #include <linux/socket.h>
57 #include <linux/if_ether.h>
58 #include <linux/if_arp.h>
59 #include <linux/if_packet.h>
60 #include <linux/llc.h>
61 #define __GLIBC__
62
63
64 struct llcdrv_nat
65 {
66   LLCDRV;
67   int fd;
68   unsigned char smac[ETH_ALEN];
69   int sap;
70   char *name;
71 };
72
73 #ifdef DEBUG
74 static void
75 hexdump (char *p, unsigned char *buf, int l)
76 {
77   int i;
78
79   for (i = 0; i < l; ++i)
80     {
81       if ((i % 16) == 0)
82         {
83           printf ("%s: ", p);
84         }
85       printf ("%02x ", buf[i]);
86       if ((i % 16) == 15)
87         {
88           printf ("\n");
89         }
90     }
91
92   printf ("\n");
93
94
95 }
96 #endif
97
98 static void
99 get_hwaddr (unsigned char *name, unsigned char *addr)
100 {
101   struct ifreq ifr;
102   int fd = socket (AF_INET, SOCK_DGRAM, 0);
103
104   if (fd < 0)
105     {
106       syslog (LOG_ERR, "socket:%m");
107       return;
108     }
109   bcopy (name, &ifr.ifr_name, sizeof (ifr.ifr_name));
110
111
112   /* find my own hardware address */
113   if (ioctl (fd, SIOCGIFHWADDR, &ifr) < 0)
114     {
115       close (fd);
116       syslog (LOG_ERR, "ioctl(SIOCGIFHWADDR):%m");
117       exit (-1);
118     }
119   close (fd);
120
121   bcopy (&ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
122
123 }
124
125 static int
126 llc_nat_send (struct llcdrv *llc, unsigned char *dmac, unsigned char dsap,
127               unsigned char *buf, int len)
128 {
129   struct llcdrv_nat *llc_nat = (struct llcdrv_nat *) llc;
130   struct sockaddr_llc sllc;
131
132   sllc.sllc_family = AF_LLC;
133
134   sllc.sllc_ssap = llc_nat->sap;
135   bcopy (llc_nat->smac, sllc.sllc_smac, ETH_ALEN);
136
137   sllc.sllc_dsap = dsap;
138   bcopy (dmac, sllc.sllc_dmac, ETH_ALEN);
139
140 #ifdef DEBUG
141   printf ("Sending %d bytes from %d (%s)",
142           len, sllc.sllc_ssap, ethtoa (sllc.sllc_smac));
143   printf ("                to %d (%s)\n",
144           sllc.sllc_dsap, ethtoa (sllc.sllc_dmac));
145
146 //  hexdump ("write", buf, len);
147 #endif
148
149   return sendto (llc_nat->fd, buf, len, 0, &sllc, sizeof (sllc));
150
151
152 }
153
154
155 static int
156 llc_nat_recv (struct llcdrv *llc, unsigned char *buf, int len,
157               unsigned char *smac, unsigned char *ssap, struct timeval *tv)
158 {
159   struct llcdrv_nat *llc_nat = (struct llcdrv_nat *) llc;
160   struct sockaddr_llc sllc;
161   int fromlen = sizeof (sllc);
162   fd_set rfds;
163   int ret;
164
165   FD_ZERO (&rfds);
166   FD_SET (llc_nat->fd, &rfds);
167
168   ret = select ((llc_nat->fd) + 1, &rfds, NULL, NULL, tv);
169
170   if (ret < 0)
171     return (ret);
172
173   if (!FD_ISSET ((llc_nat->fd), &rfds))
174     return 0;
175
176   ret = recvfrom (llc_nat->fd, buf, len, 0, &sllc, &fromlen);
177
178
179   if (smac)
180     bcopy (sllc.sllc_smac, smac, ETH_ALEN);
181   if (ssap)
182     *ssap = sllc.sllc_ssap;
183
184 #ifdef DEBUG
185   printf ("llc-nat-recv: source: %s ", ethtoa (sllc.sllc_smac));
186   printf ("len: 0x%04x ", ret);
187   printf ("dsap:%02x ssap:%02x \n", sllc.sllc_dsap, sllc.sllc_ssap);
188 #endif
189
190   return ret;
191
192 }
193
194 static int
195 llc_nat_add_multicast (struct llcdrv *llc, unsigned char *mac)
196 {
197   struct llcdrv_nat *llc_nat = (struct llcdrv_nat *) llc;
198   struct ifreq ifr;
199   int fd = socket (AF_INET, SOCK_DGRAM, 0);
200
201   strncpy (ifr.ifr_name, llc_nat->name, sizeof (ifr.ifr_name));
202
203   ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
204
205   bcopy (mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
206
207   if (ioctl (fd, SIOCADDMULTI, &ifr) < 0)
208     {
209       close (fd);
210       syslog (LOG_ERR, "ioctl(SIOCADDMULTI):%m");
211       return -1;
212     }
213
214   return 0;
215 }
216
217 static unsigned char *
218 llc_nat_mac (struct llcdrv *llc)
219 {
220   struct llcdrv_nat *llc_nat = (struct llcdrv_nat *) llc;
221   return llc_nat->smac;
222 }
223
224 static void
225 llc_nat_close (struct llcdrv *llc)
226 {
227   struct llcdrv_nat *llc_nat = (struct llcdrv_nat *) llc;
228   close (llc_nat->fd);
229   free (llc_nat);
230 }
231
232 struct llcdrv *
233 llc_open (unsigned char sap, char *name)
234 {
235   struct llcdrv_nat *llc_nat;
236   struct sockaddr_llc sllc;
237
238
239   llc_nat = malloc (sizeof (struct llcdrv_nat));
240   bzero (llc_nat, sizeof (struct llcdrv));
241
242   llc_nat->fd = socket (PF_LLC, SOCK_DGRAM, 0);
243   if (llc_nat->fd < 0)
244     {
245       syslog (LOG_ERR, "socket:%m");
246       free (llc_nat);
247       return NULL;
248     }
249
250   if (!name)
251     name = "eth0";
252
253   get_hwaddr (name, llc_nat->smac);
254
255   llc_nat->sap = sap;
256
257   bzero (&sllc, sizeof (sllc));
258   sllc.sllc_family = AF_LLC;
259   sllc.sllc_ssap = sap;
260   sllc.sllc_dsap = sap;
261   bcopy (llc_nat->smac, &sllc.sllc_smac, ETH_ALEN);
262
263   if (bind (llc_nat->fd, &sllc, sizeof (sllc)) < 0)
264     {
265       close (llc_nat->fd);
266       free (llc_nat);
267       syslog (LOG_ERR, "bind:%m");
268       return NULL;
269     }
270
271   llc_nat->recv = llc_nat_recv;
272   llc_nat->send = llc_nat_send;
273   llc_nat->mac = llc_nat_mac;
274   llc_nat->add_multicast = llc_nat_add_multicast;
275   llc_nat->close = llc_nat_close;
276   llc_nat->name = strdup (name);
277
278
279   return (struct llcdrv *) llc_nat;
280 }