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