http://gimel.esc.cam.ac.uk/james/rpld/src/rpld-1.2.tar.gz
[rpld.git] / linux-ps.c
1 /*************************************************
2 *     rpld - an IBM style RIPL server            *
3 *************************************************/
4
5 /* Copyright (c) 1999, 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
19 static char rcsid[] = "$Id: linux-ps.c,v 1.6 2000/07/16 13:18:10 root Exp root $";
20
21 /* 
22  * $Log: linux-ps.c,v $
23  * Revision 1.6  2000/07/16 13:18:10  root
24  * #
25  *
26  * Revision 1.1  2000/07/16 13:16:33  root
27  * #
28  *
29  * Revision 1.5  1999/09/13 11:17:35  root
30  * \#
31  *
32  * Revision 1.4  1999/09/11 16:52:15  root
33  * \#
34  *
35  * Revision 1.3  1999/09/11 16:34:50  root
36  * \#
37  *
38  * Revision 1.2  1999/09/10 22:06:43  root
39  * \#
40  *
41  * Revision 1.1  1999/09/10 17:32:26  root
42  * \#
43  *
44  * Revision 1.1  1999/05/17 21:53:33  root
45  * Initial revision
46  *
47  */
48
49 /*
50  * CAUTION THIS CODE COMES WITH NO WARARNTY IT IS COPYRIGHT 1999 BY
51  * James McKenzie All rights reserved. GPL applies
52  */
53
54
55 #include "project.h"
56
57 #undef __GLIBC__
58 #include <linux/socket.h>
59 #include <linux/if_ether.h>
60 #include <linux/if_arp.h>
61 #include <linux/if_packet.h>
62 #include <linux/route.h>
63 #define __GLIBC__
64
65
66
67 static void
68 get_hwaddr (unsigned char *name, unsigned char *addr)
69 {
70   struct ifreq ifr;
71   int fd = socket (AF_INET, SOCK_DGRAM, 0);
72
73   if (fd < 0)
74     {
75       syslog (LOG_ERR, "socket:%m");
76       return;
77     }
78   bcopy (name, &ifr.ifr_name, sizeof (ifr.ifr_name));
79
80
81   /* find my own hardware address */
82   if (ioctl (fd, SIOCGIFHWADDR, &ifr) < 0)
83     {
84       close (fd);
85       syslog (LOG_ERR, "ioctl(SIOCGIFHWADDR):%m");
86       exit (-1);
87     }
88   close (fd);
89
90
91   bcopy (&ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
92
93 }
94
95 void
96 nit_close (struct nit *n)
97 {
98   if (!n)
99     return;
100
101   close (n->fd);
102   free (n->name);
103
104 /*FIXME: we should demulticast at this point but we need to have some 
105  *mechanism for detecting if anyone else wants it
106  */
107
108   free (n);
109 }
110
111 struct nit *
112 nit_open (char *name)
113 {
114   struct nit *n;
115   struct sockaddr sa;
116   int fd;
117
118   if (!name)
119     name = "eth0";
120
121   fd = socket (PF_PACKET, SOCK_PACKET, htons (ETH_P_ALL));
122
123   if (fd < 0)
124     fd = socket (AF_INET, SOCK_PACKET, htons (ETH_P_ALL));
125
126   if (fd < 0)
127     {
128       syslog (LOG_ERR, "socket:%m");
129       return (NULL);
130     }
131
132   bzero (&sa, sizeof (sa));
133   sa.sa_family = AF_INET;
134   memcpy (&sa.sa_data, name, sizeof (sa.sa_data));
135
136   if (bind (fd, &sa, sizeof (sa)) < 0)
137     {
138       close (fd);
139       syslog (LOG_ERR, "bind:%m");
140       return (NULL);
141     }
142
143
144   n = (struct nit *) malloc (sizeof (struct nit));
145
146   n->fd = fd;
147   n->name = (char *) malloc (MAX_NAME_LEN);
148   bzero (n->name, MAX_NAME_LEN);
149
150   strcpy (n->name, name);
151   get_hwaddr (n->name, n->mac);
152
153   return (n);
154 }
155
156 void
157 nit_send_frame (struct nit *n, unsigned char *frame, int len)
158 {
159   struct sockaddr sa;
160   struct msghdr msg;
161   struct iovec iov;
162
163   bzero (&msg, sizeof (msg));
164   bzero (&sa, sizeof (sa));
165
166   sa.sa_family = AF_INET;
167   strncpy (sa.sa_data, n->name, sizeof (sa.sa_data));
168
169   if (sendto (n->fd, frame, len, 0, &sa, sizeof (sa)) < 0)
170     syslog (LOG_ERR, "sendto: %m");
171
172   return;
173
174 }
175
176
177 void
178 nit_multicast (struct nit *n, unsigned char *mcaddr)
179 {
180   struct ifreq ifr;
181   int fd = socket (AF_INET, SOCK_DGRAM, 0);
182
183   strncpy (ifr.ifr_name, n->name, sizeof (ifr.ifr_name));
184
185   ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
186
187   bcopy (mcaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
188
189   if (ioctl (fd, SIOCADDMULTI, &ifr) < 0)
190     {
191       close (fd);
192       syslog (LOG_ERR, "ioctl(SIOCADDMULTI):%m");
193     }
194 }
195
196 int
197 nit_read_packet (struct nit *n, char *buf, int len, struct timeval *tv)
198 {
199   fd_set rfds;
200   int ret;
201
202   FD_ZERO (&rfds);
203   FD_SET (n->fd, &rfds);
204
205
206   ret = select ((n->fd) + 1, &rfds, NULL, NULL, tv);
207
208   if (ret < 0)
209     return (ret);
210
211   if (FD_ISSET ((n->fd), &rfds))
212     {
213
214       ret = read (n->fd, buf, len);
215
216       return (ret);
217     }
218   else
219     {
220       return (0);
221     }
222
223 }