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