Added sample rpld.conf file to load gPXE
[rpld.git] / linux-old-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,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 static char rcsid[] =
19   "$Id: linux-old-nit.c,v 1.3 2001/11/01 15:24:26 root Exp $";
20
21 /* 
22  * $Log: linux-old-nit.c,v $
23  * Revision 1.3  2001/11/01 15:24:26  root
24  * #
25  *
26  * Revision 1.2  2000/09/26 03:48:23  root
27  * #
28  *
29  * Revision 1.1  2000/09/26 03:45:34  root
30  * #
31  *
32  *
33  */
34
35 /*
36  * CAUTION THIS CODE COMES WITH NO WARARNTY IT IS COPYRIGHT 1999 BY
37  * James McKenzie All rights reserved. GPL applies
38  */
39
40
41
42 #include "project.h"
43 #include "nit.h"
44
45 #undef __GLIBC__
46 #include <linux/socket.h>
47 #include <linux/if_ether.h>
48 #include <linux/if_arp.h>
49 #include <linux/if_packet.h>
50 #include <linux/route.h>
51 #define __GLIBC__
52
53
54
55 #define NIT_MAX_NAME_LEN 1024
56
57 struct nit
58 {
59   int fd;
60   char *name;
61   unsigned char mac[6];
62 };
63
64 struct machdr
65 {
66   unsigned char h_dest[ETH_ALEN];
67   unsigned char h_source[ETH_ALEN];
68   short h_len;
69 };
70
71
72
73 static void
74 get_hwaddr (unsigned char *name, unsigned char *addr)
75 {
76   struct ifreq ifr;
77   int fd = socket (AF_INET, SOCK_DGRAM, 0);
78
79   if (fd < 0)
80     {
81       syslog (LOG_ERR, "socket:%m");
82       return;
83     }
84   bcopy (name, &ifr.ifr_name, sizeof (ifr.ifr_name));
85
86
87   /* find my own hardware address */
88   if (ioctl (fd, SIOCGIFHWADDR, &ifr) < 0)
89     {
90       close (fd);
91       syslog (LOG_ERR, "ioctl(SIOCGIFHWADDR):%m");
92       exit (-1);
93     }
94   close (fd);
95
96
97   bcopy (&ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
98
99 }
100
101 unsigned char *
102 nit_mac (struct nit *n)
103 {
104   return n->mac;
105 }
106
107 void
108 nit_close (struct nit *n)
109 {
110   if (!n)
111     return;
112
113   close (n->fd);
114   free (n->name);
115
116 /*FIXME: we should demulticast at this point but we need to have some 
117  *mechanism for detecting if anyone else wants it
118  */
119
120   free (n);
121 }
122
123 struct nit *
124 nit_open (char *name)
125 {
126   struct nit *n;
127   struct sockaddr sa;
128   int fd;
129
130   syslog (LOG_ERR, "RPLD OLD LINUX-NIT support %s", rcsid);
131
132   if (!name)
133     name = "eth0";
134
135 #ifdef PF_PACKET
136   fd = socket (PF_PACKET, SOCK_PACKET, htons (ETH_P_ALL));
137
138   if (fd < 0)
139 #endif
140     fd = socket (AF_INET, SOCK_PACKET, htons (ETH_P_ALL));
141
142   if (fd < 0)
143     {
144       syslog (LOG_ERR, "socket:%m");
145       return (NULL);
146     }
147
148   bzero (&sa, sizeof (sa));
149   sa.sa_family = AF_INET;
150   memcpy (&sa.sa_data, name, sizeof (sa.sa_data));
151
152   if (bind (fd, &sa, sizeof (sa)) < 0)
153     {
154       close (fd);
155       syslog (LOG_ERR, "bind:%m");
156       return (NULL);
157     }
158
159
160   n = (struct nit *) malloc (sizeof (struct nit));
161
162   n->fd = fd;
163   n->name = (char *) malloc (NIT_MAX_NAME_LEN);
164   bzero (n->name, NIT_MAX_NAME_LEN);
165
166   strcpy (n->name, name);
167   get_hwaddr (n->name, n->mac);
168
169   return (n);
170 }
171
172 int
173 nit_send (struct nit *n, unsigned char *frame, int len, unsigned char *to)
174 {
175   struct sockaddr sa;
176   int mylen;
177   unsigned char *myframe = malloc (len + sizeof (struct machdr));
178   struct machdr *mh = (struct machdr *) myframe;
179
180   bcopy (to, mh->h_dest, ETH_ALEN);
181   bcopy (n->mac, mh->h_source, ETH_ALEN);
182   mh->h_len = htons (len);
183
184   bcopy (frame, myframe + sizeof (struct machdr), len);
185   mylen = len + sizeof (struct machdr);
186
187   bzero (&sa, sizeof (sa));
188   sa.sa_family = AF_INET;
189   strncpy (sa.sa_data, n->name, sizeof (sa.sa_data));
190
191 #ifdef DEBUG
192 //  hexdump("out",myframe,mylen);
193 #endif
194
195   if (sendto (n->fd, myframe, mylen, 0, &sa, sizeof (sa)) < 0)
196     syslog (LOG_ERR, "sendto: %m");
197
198
199
200   free (myframe);
201
202
203   return len;
204
205 }
206
207
208 int
209 nit_multicast (struct nit *n, unsigned char *mcaddr)
210 {
211   struct ifreq ifr;
212   int fd = socket (AF_INET, SOCK_DGRAM, 0);
213
214   strncpy (ifr.ifr_name, n->name, sizeof (ifr.ifr_name));
215
216   ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
217
218   bcopy (mcaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
219
220   if (ioctl (fd, SIOCADDMULTI, &ifr) < 0)
221     {
222       close (fd);
223       syslog (LOG_ERR, "ioctl(SIOCADDMULTI):%m");
224       return -1;
225     }
226   return 0;
227 }
228
229 int
230 nit_recv (struct nit *n, unsigned char *buf, int len, unsigned char *from,
231           struct timeval *tv)
232 {
233   fd_set rfds;
234   int ret;
235
236   struct machdr *mh;
237
238
239   buf -= sizeof (struct machdr);
240   mh = (struct machdr *) buf;
241
242   FD_ZERO (&rfds);
243   FD_SET (n->fd, &rfds);
244
245
246   ret = select ((n->fd) + 1, &rfds, NULL, NULL, tv);
247
248   if (ret < 0)
249     return (ret);
250
251   if (FD_ISSET ((n->fd), &rfds))
252     {
253
254       ret = read (n->fd, buf, len);
255
256       if (ret > sizeof (struct machdr))
257         {
258
259           if (from)
260             bcopy (mh->h_source, from, ETH_ALEN);
261           ret = htons (mh->h_len);
262
263           if (ret > len)
264             {
265               ret = len;
266             }
267
268           return (ret);
269         }
270       else
271         {
272           return 0;
273         }
274
275     }
276   else
277     {
278       return (0);
279     }
280
281 }