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