Added sample rpld.conf file to load gPXE
[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 <stdlib.h>
80 #include <sys/socket.h>
81 #include <linux/if_ether.h>
82 #include <linux/if_arp.h>
83 #include <linux/if_packet.h>
84 #include <sys/ioctl.h>
85 #include <sys/uio.h>
86
87 #if 0
88 /* Dire libc5 hack */
89 #undef __GLIBC__
90 #include <linux/socket.h>
91 #include <linux/if_ether.h>
92 #include <linux/if_arp.h>
93 #include <linux/if_packet.h>
94 #include <asm/socket.h>
95 #define __GLIBC__
96 #endif
97
98 struct nit
99 {
100   int fd;
101   int index;
102   unsigned char mac[ETH_ALEN];
103   char *name;
104 };
105
106
107 static void
108 get_hwaddr (char *name, unsigned char *addr)
109 {
110   struct ifreq ifr;
111   int fd = socket (AF_INET, SOCK_DGRAM, 0);
112
113   if (fd < 0)
114     {
115       syslog (LOG_ERR, "socket:%m");
116       return;
117     }
118   bcopy (name, &ifr.ifr_name, sizeof (ifr.ifr_name));
119
120
121   /* find my own hardware address */
122   if (ioctl (fd, SIOCGIFHWADDR, &ifr) < 0)
123     {
124       close (fd);
125       syslog (LOG_ERR, "ioctl(SIOCGIFHWADDR):%m");
126       exit (-1);
127     }
128   close (fd);
129
130   bcopy (&ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
131
132 }
133
134 void
135 nit_close (struct nit *n)
136 {
137   if (!n)
138     return;
139
140   if (n->name)
141     free (n->name);
142   close (n->fd);
143
144 /*FIXME: we should demulticast at this point but we need to have some 
145  *mechanism for detecting if anyone else wants it
146  */
147
148   free (n);
149 }
150
151 struct nit *
152 nit_open (char *name)
153 {
154   struct nit *n;
155   struct sockaddr_ll sll;
156   struct ifreq ifr;
157   int fd;
158
159   syslog (LOG_ERR, "RPLD 802.2 LINUX-NIT support %s", rcsid);
160
161   fd = socket (PF_PACKET, SOCK_DGRAM, 0);
162
163   if (fd < 0)
164     {
165       syslog (LOG_ERR, "socket:%m");
166       return (NULL);
167     }
168
169   ifr.ifr_ifindex = 0;
170   if (name)
171     {
172
173       strcpy (ifr.ifr_name, name);
174
175       if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
176         {
177           syslog (LOG_ERR, "SIOCGIFINDEX on %s: %m\n", name);
178           close (fd);
179           return NULL;
180         }
181
182     }
183
184
185
186   bzero (&sll, sizeof (sll));
187   sll.sll_family = AF_PACKET;
188   sll.sll_protocol = htons (ETH_P_802_2);
189   sll.sll_ifindex = ifr.ifr_ifindex;
190
191   if (bind (fd, (struct sockaddr *) &sll, sizeof (sll)) < 0)
192     {
193       close (fd);
194       syslog (LOG_ERR, "bind:%m");
195       return (NULL);
196     }
197
198
199   n = (struct nit *) malloc (sizeof (struct nit));
200
201   n->index = ifr.ifr_ifindex;
202
203   n->fd = fd;
204
205   get_hwaddr (name, n->mac);
206
207   if (name)
208     {
209       n->name = strdup (name);
210     }
211   else
212     {
213       n->name = NULL;
214     }
215
216   return (n);
217 }
218
219 unsigned char *
220 nit_mac (struct nit *n)
221 {
222   return (n->mac);
223 }
224
225 int
226 nit_send (struct nit *n, unsigned char *frame, int len, unsigned char *to)
227 {
228   struct sockaddr_ll sll;
229   struct msghdr msg;
230   struct iovec iov;
231
232   bzero (&msg, sizeof (msg));
233   bzero (&sll, sizeof (sll));
234
235
236   sll.sll_family = AF_PACKET;
237 /* This is the most horrible hack you are ever likely to see*/
238 /* if you don't understand what's happening in the line below*/
239 /* be very very happy */
240   sll.sll_protocol = htons (len);
241   sll.sll_ifindex = n->index;
242   sll.sll_hatype = ARPHRD_ETHER;
243   sll.sll_pkttype = PACKET_OUTGOING;
244   sll.sll_halen = ETH_ALEN;
245   bcopy (to, &sll.sll_addr[0], ETH_ALEN);
246
247   if (sendto (n->fd, frame, len, 0, (struct sockaddr *) &sll, sizeof (sll)) <
248       0)
249     {
250       syslog (LOG_ERR, "sendto: %m");
251       return -1;
252     }
253
254   return len;
255
256 }
257
258
259 int
260 nit_multicast (struct nit *n, unsigned char *mcaddr)
261 {
262   struct ifreq ifr;
263   int fd = socket (AF_INET, SOCK_DGRAM, 0);
264
265   strncpy (ifr.ifr_name, n->name, sizeof (ifr.ifr_name));
266
267   ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
268
269   bcopy (mcaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
270
271   if (ioctl (fd, SIOCADDMULTI, &ifr) < 0)
272     {
273       close (fd);
274       syslog (LOG_ERR, "ioctl(SIOCADDMULTI):%m");
275       return -1;
276     }
277
278   return 0;
279 }
280
281 int
282 nit_recv (struct nit *n, unsigned char *buf, int len, unsigned char *ufrom,
283           struct timeval *tv)
284 {
285   fd_set rfds;
286   int ret;
287   struct sockaddr_ll from;
288   socklen_t fromlen = sizeof (from);
289
290
291   FD_ZERO (&rfds);
292   FD_SET (n->fd, &rfds);
293
294   ret = select ((n->fd) + 1, &rfds, NULL, NULL, tv);
295
296   if (ret < 0)
297     return (ret);
298
299   if (FD_ISSET ((n->fd), &rfds))
300     {
301       ret =
302         recvfrom (n->fd, buf, len, 0, (struct sockaddr *) &from, &fromlen);
303       if (ufrom)
304         bcopy (from.sll_addr, ufrom, ETH_ALEN);
305
306       return (ret);
307     }
308   else
309     {
310       return (0);
311     }
312
313 }