bef3c92ca849e8188b3b2f9d423e6eeb9bef29ee
[rpld.git] / linux-nit.c
1 /*************************************************
2 *     rpld - an IBM style RIPL server            *
3 *************************************************/
4
5 /* Copyright (c) 1999,2000,2001 James McKenzie.
6  *                      All rights reserved
7  * Copyright (c) 1998,2000,2001 Christopher Lightfoot.
8  *                      All rights reserved
9  *
10  * By using this file, you agree to the terms and conditions set
11  * forth in the LICENCE file which can be found at the top level of
12  * the rpld distribution.
13  *
14  * IBM is a trademark of IBM corp.
15  *
16  */
17
18
19 static char rcsid[] = "$Id: linux-nit.c,v 1.5 2001/11/01 15:26:29 root Exp $";
20
21 /* 
22  * $Log: linux-nit.c,v $
23  * Revision 1.5  2001/11/01 15:26:29  root
24  * #
25  *
26  * Revision 1.4  2001/11/01 15:24:26  root
27  * #
28  *
29  * Revision 1.3  2001/11/01 15:23:59  root
30  * #
31  *
32  * Revision 1.2  2000/09/26 03:48:23  root
33  * #
34  *
35  * Revision 1.1  2000/09/26 03:44:29  root
36  * #
37  *
38  * Revision 1.8  2000/07/16 14:24:16  root
39  * #
40  *
41  * Revision 1.7  2000/07/16 14:05:28  root
42  * #
43  *
44  * Revision 1.6  2000/07/16 13:18:10  root
45  * #
46  *
47  * Revision 1.1  2000/07/16 13:16:33  root
48  * #
49  *
50  * Revision 1.5  1999/09/13 11:17:35  root
51  * \#
52  *
53  * Revision 1.4  1999/09/11 16:52:15  root
54  * \#
55  *
56  * Revision 1.3  1999/09/11 16:34:50  root
57  * \#
58  *
59  * Revision 1.2  1999/09/10 22:06:43  root
60  * \#
61  *
62  * Revision 1.1  1999/09/10 17:32:26  root
63  * \#
64  *
65  * Revision 1.1  1999/05/17 21:53:33  root
66  * Initial revision
67  *
68  */
69
70 /*
71  * CAUTION THIS CODE COMES WITH NO WARARNTY IT IS COPYRIGHT 1999 BY
72  * James McKenzie All rights reserved. GPL applies
73  */
74
75
76 #include "project.h"
77 #include "nit.h"
78
79 #include <sys/socket.h>
80 #include <linux/if_ether.h>
81 #include <linux/if_arp.h>
82 #include <linux/if_packet.h>
83 #include <sys/ioctl.h>
84 #include <sys/uio.h>
85
86 #if 0
87 /* Dire libc5 hack */
88 #undef __GLIBC__
89 #include <linux/socket.h>
90 #include <linux/if_ether.h>
91 #include <linux/if_arp.h>
92 #include <linux/if_packet.h>
93 #include <asm/socket.h>
94 #define __GLIBC__
95 #endif
96
97 struct nit
98 {
99   int fd;
100   int index;
101   unsigned char mac[ETH_ALEN];
102   char *name;
103 };
104
105
106 static void
107 get_hwaddr (unsigned char *name, unsigned char *addr)
108 {
109   struct ifreq ifr;
110   int fd = socket (AF_INET, SOCK_DGRAM, 0);
111
112   if (fd < 0)
113     {
114       syslog (LOG_ERR, "socket:%m");
115       return;
116     }
117   bcopy (name, &ifr.ifr_name, sizeof (ifr.ifr_name));
118
119
120   /* find my own hardware address */
121   if (ioctl (fd, SIOCGIFHWADDR, &ifr) < 0)
122     {
123       close (fd);
124       syslog (LOG_ERR, "ioctl(SIOCGIFHWADDR):%m");
125       exit (-1);
126     }
127   close (fd);
128
129   bcopy (&ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
130
131 }
132
133 void
134 nit_close (struct nit *n)
135 {
136   if (!n)
137     return;
138
139   if (n->name)
140     free (n->name);
141   close (n->fd);
142
143 /*FIXME: we should demulticast at this point but we need to have some 
144  *mechanism for detecting if anyone else wants it
145  */
146
147   free (n);
148 }
149
150 struct nit *
151 nit_open (char *name)
152 {
153   struct nit *n;
154   struct sockaddr_ll sll;
155   struct ifreq ifr;
156   int fd;
157
158   syslog (LOG_ERR, "RPLD 802.2 LINUX-NIT support %s", rcsid);
159
160   fd = socket (PF_PACKET, SOCK_DGRAM, 0);
161
162   if (fd < 0)
163     {
164       syslog (LOG_ERR, "socket:%m");
165       return (NULL);
166     }
167
168   ifr.ifr_ifindex = 0;
169   if (name)
170     {
171
172       strcpy (ifr.ifr_name, name);
173
174       if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
175         {
176           syslog (LOG_ERR, "SIOCGIFINDEX on %s: %m\n", name);
177           close (fd);
178           return NULL;
179         }
180
181     }
182
183
184
185   bzero (&sll, sizeof (sll));
186   sll.sll_family = AF_PACKET;
187   sll.sll_protocol = htons (ETH_P_802_2);
188   sll.sll_ifindex = ifr.ifr_ifindex;
189
190   if (bind (fd, (struct sockaddr *) &sll, sizeof (sll)) < 0)
191     {
192       close (fd);
193       syslog (LOG_ERR, "bind:%m");
194       return (NULL);
195     }
196
197
198   n = (struct nit *) malloc (sizeof (struct nit));
199
200   n->index = ifr.ifr_ifindex;
201
202   n->fd = fd;
203
204   get_hwaddr (name, n->mac);
205
206   if (name)
207     {
208       n->name = strdup (name);
209     }
210   else
211     {
212       n->name = NULL;
213     }
214
215   return (n);
216 }
217
218 unsigned char *
219 nit_mac (struct nit *n)
220 {
221   return (n->mac);
222 }
223
224 int
225 nit_send (struct nit *n, unsigned char *frame, int len, unsigned char *to)
226 {
227   struct sockaddr_ll sll;
228   struct msghdr msg;
229   struct iovec iov;
230
231   bzero (&msg, sizeof (msg));
232   bzero (&sll, sizeof (sll));
233
234
235   sll.sll_family = AF_PACKET;
236 /* This is the most horrible hack you are ever likely to see*/
237 /* if you don't understand what's happening in the line below*/
238 /* be very very happy */
239   sll.sll_protocol = htons (len);
240   sll.sll_ifindex = n->index;
241   sll.sll_hatype = ARPHRD_ETHER;
242   sll.sll_pkttype = PACKET_OUTGOING;
243   sll.sll_halen = ETH_ALEN;
244   bcopy (to, &sll.sll_addr[0], ETH_ALEN);
245
246   if (sendto (n->fd, frame, len, 0, (struct sockaddr *) &sll, sizeof (sll)) <
247       0)
248     {
249       syslog (LOG_ERR, "sendto: %m");
250       return -1;
251     }
252
253   return len;
254
255 }
256
257
258 int
259 nit_multicast (struct nit *n, unsigned char *mcaddr)
260 {
261   struct ifreq ifr;
262   int fd = socket (AF_INET, SOCK_DGRAM, 0);
263
264   strncpy (ifr.ifr_name, n->name, sizeof (ifr.ifr_name));
265
266   ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
267
268   bcopy (mcaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
269
270   if (ioctl (fd, SIOCADDMULTI, &ifr) < 0)
271     {
272       close (fd);
273       syslog (LOG_ERR, "ioctl(SIOCADDMULTI):%m");
274       return -1;
275     }
276
277   return 0;
278 }
279
280 int
281 nit_recv (struct nit *n, unsigned char *buf, int len, unsigned char *ufrom,
282           struct timeval *tv)
283 {
284   fd_set rfds;
285   int ret;
286   struct sockaddr_ll from;
287   int fromlen = sizeof (from);
288
289
290   FD_ZERO (&rfds);
291   FD_SET (n->fd, &rfds);
292
293   ret = select ((n->fd) + 1, &rfds, NULL, NULL, tv);
294
295   if (ret < 0)
296     return (ret);
297
298   if (FD_ISSET ((n->fd), &rfds))
299     {
300       ret =
301         recvfrom (n->fd, buf, len, 0, (struct sockaddr *) &from, &fromlen);
302       if (ufrom)
303         bcopy (from.sll_addr, ufrom, ETH_ALEN);
304
305       return (ret);
306     }
307   else
308     {
309       return (0);
310     }
311
312 }