http://gimel.esc.cam.ac.uk/james/rpld/src/rpld-1.3.tar.gz
[rpld.git] / rpl.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
20 static char rcsid[] = "$Id: rpl.c,v 1.7 1999/09/13 11:17:35 root Exp $";
21
22 /*
23  * $Log: rpl.c,v $
24  * Revision 1.7  1999/09/13 11:17:35  root
25  * \#
26  *
27  * Revision 1.6  1999/09/13 11:08:34  root
28  * \#
29  *
30  * Revision 1.5  1999/09/13 11:05:27  root
31  * \#
32  *
33  * Revision 1.4  1999/09/13 11:04:13  root
34  * \#
35  *
36  */
37
38 #include "project.h"
39
40 /* Code for recursively disembling packets */
41
42 static void
43 rpl_token (struct rpl_packet *p, int s, unsigned char *pp, int pl)
44 {
45   int i;
46   switch (s)
47     {
48     case RPL_TK_TMZ:
49       if (pl < 4)
50         return;
51       p->flags |= RPL_FL_TMZ;
52       p->themightyzero = ntohl (*(u32 *) pp);
53       return;
54     case RPL_TK_MYMAC:
55       if (pl < ETH_ALEN)
56         return;
57       p->flags |= RPL_FL_MYMAC;
58       bcopy (pp, p->mymac, ETH_ALEN);
59       return;
60     case RPL_TK_SAP:
61       /*FIXME: */
62       p->flags |= RPL_FL_SAP;
63       return;
64     case RPL_TK_FRAMELEN:
65       if (pl < 2)
66         return;
67       p->flags |= RPL_FL_FRAMELEN;
68       p->framelen = ntohs (*(u16 *) pp);
69       return;
70     case RPL_TK_WHOAMI:
71       if (pl < 2)
72         return;
73       p->flags |= RPL_FL_WHOAMI;
74       p->whoami = ntohs (*(u16 *) pp);
75       return;
76     case RPL_TK_TSZ:
77       if (pl < 1)
78         return;
79       p->flags |= RPL_FL_TSZ;
80       p->thesmallzero = *pp;
81       return;
82     case RPL_TK_YOUMAC:
83       if (pl < ETH_ALEN)
84         return;
85       p->flags |= RPL_FL_YOUMAC;
86       bcopy (pp, p->youmac, ETH_ALEN);
87       return;
88     case RPL_TK_BLOCK:
89       if (pl < 4)
90         return;
91       p->flags |= RPL_FL_BLOCK;
92       p->block = ntohl (*(u32 *) pp);
93       return;
94     case RPL_TK_DATA:
95       if (NOTINRANGE (1, pl, MAX_DATA_LEN))
96         return;
97       p->flags |= RPL_FL_DATA;
98       bcopy (pp, p->data, pl);
99       p->datalen = pl;
100       return;
101     case RPL_TK_IDENT:
102       if (NOTINRANGE (1, pl, MAX_IDENT_LEN))
103         return;
104       p->flags |= RPL_FL_IDENT;
105       bcopy (pp, p->ident, pl);
106       p->identlen = pl;
107       return;
108     case RPL_FL_ADDR:
109       if (pl < 9)
110         return;
111       p->flags |= RPL_FL_ADDR;
112       p->addr.load = ntohl (*(u32 *) pp);
113       p->addr.run = ntohl (*(u32 *) (pp + 4));
114       p->addr.flags = pp[8];
115       return;
116     default:
117       syslog (LOG_ERR, "Unknown token: 0x%04x", s);
118     }
119
120 }
121
122 static void
123 rpl_frag (struct rpl_packet *p, unsigned char *pp, int pl)
124 {
125   int s;
126
127   while (pl > 0)
128     {
129
130       if (pl < 2)
131         return;
132       s = ntohs (*(u16 *) pp);
133
134       if (!s)
135         {
136           syslog (LOG_ERR, "Unexpected end of packet", s);
137           return;
138
139         }
140       if (RPL_IS_TOKEN (s))
141         {
142           rpl_token (p, s, pp + 2, pl - 2);
143           return;
144         }
145       else
146         {
147           rpl_frag (p, pp + 2, s - 2);
148           pp += s;
149           pl -= s;
150         }
151
152     }
153
154 }
155
156 /* Code for assembling packets */
157 int
158 write_char (unsigned char *ptr, u8 v)
159 {
160   *ptr = v;
161   return (1);
162 }
163 int
164 write_short (unsigned char *ptr, u16 v)
165 {
166   *((u16 *) ptr) = htons (v);
167   return (2);
168 }
169 int
170 write_long (unsigned char *ptr, u32 v)
171 {
172   *((u32 *) ptr) = htonl (v);
173   return (4);
174 }
175
176 int
177 put_char (unsigned char *ptr, u16 token, u8 value)
178 {
179   int len = 0, i;
180   i = write_short (ptr, 0x2 + 0x2 + 0x1);
181   ptr += i;
182   len += i;
183   i = write_short (ptr, token);
184   ptr += i;
185   len += i;
186   i = write_char (ptr, value);
187   ptr += i;
188   len += i;
189   return (len);
190 }
191 int
192 put_short (unsigned char *ptr, u16 token, u16 value)
193 {
194   int len = 0, i;
195   i = write_short (ptr, 0x2 + 0x2 + 0x2);
196   ptr += i;
197   len += i;
198   i = write_short (ptr, token);
199   ptr += i;
200   len += i;
201   i = write_short (ptr, value);
202   ptr += i;
203   len += i;
204   return (len);
205 }
206 int
207 put_long (unsigned char *ptr, u16 token, u32 value)
208 {
209   int len = 0, i;
210   i = write_short (ptr, 0x2 + 0x2 + 0x4);
211   ptr += i;
212   len += i;
213   i = write_short (ptr, token);
214   ptr += i;
215   len += i;
216   i = write_long (ptr, value);
217   ptr += i;
218   len += i;
219   return (len);
220 }
221 int
222 put_mac (unsigned char *ptr, u16 token, unsigned char *mac)
223 {
224   int len = 0, i;
225   i = write_short (ptr, 0x2 + 0x2 + 0x6);
226   ptr += i;
227   len += i;
228   i = write_short (ptr, token);
229   ptr += i;
230   len += i;
231   bcopy (mac, ptr, ETH_ALEN);
232   ptr += ETH_ALEN;
233   len += ETH_ALEN;
234   return (len);
235 }
236
237 static void
238 send_found_frame (struct nit *n, unsigned char *dmac, struct rpl_packet *out)
239 {
240   unsigned char buf[MAX_FRAME_LEN], *ptr;
241   int len, i;
242
243   if (out->flags != RPL_FOUND_FLAGS)
244     {
245
246       syslog (LOG_ERR, "FOUND packet: doesn't match RE case %x!=%x",
247               out->flags, RPL_FOUND_FLAGS);
248       return;
249     }
250
251   ptr = buf;
252   len = 0;
253
254   i = write_short (ptr, 0x0);
255   ptr += i;
256   len += i;                     /*length */
257   i = write_short (ptr, out->type);
258   ptr += i;
259   len += i;                     /*type */
260
261   i = put_long (ptr, RPL_TK_TMZ, out->themightyzero);
262   ptr += i;
263   len += i;
264   i = put_char (ptr, RPL_TK_TSZ, out->thesmallzero);
265   ptr += i;
266   len += i;
267   i = put_mac (ptr, RPL_TK_YOUMAC, out->youmac);
268   ptr += i;
269   len += i;
270   i = put_mac (ptr, RPL_TK_MYMAC, out->mymac);
271   ptr += i;
272   len += i;
273   i = write_short (ptr, 0x10);
274   ptr += i;
275   len += i;
276   i = write_short (ptr, 0x08);
277   ptr += i;
278   len += i;
279   i = put_short (ptr, RPL_TK_FRAMELEN, out->framelen);
280   ptr += i;
281   len += i;
282   i = put_short (ptr, RPL_TK_WHOAMI, out->whoami);
283   ptr += i;
284   len += i;
285   i = put_char (ptr, RPL_TK_SAP, out->sap);
286   ptr += i;
287   len += i;
288
289   ptr = buf;
290   write_short (ptr, len);       /*length */
291
292   send_llc_frame (n, RPL_SAP, RPL_SAP, dmac, buf, len);
293
294 }
295
296
297 static void
298 send_file_data_frame (struct nit *n, unsigned char *dmac, struct rpl_packet *out)
299 {
300   unsigned char buf[MAX_FRAME_LEN], *ptr;
301   int len, i;
302
303   if (out->flags != RPL_FILE_DATA_FLAGS)
304     {
305       syslog (LOG_ERR, "FILE.DATA packet: doesn't match RE case %x!=%x",
306               out->flags, RPL_FILE_DATA_FLAGS);
307       return;
308     }
309
310   ptr = buf;
311   len = 0;
312
313   i = write_short (ptr, 0x0);
314   ptr += i;
315   len += i;                     /*length */
316   i = write_short (ptr, out->type);
317   ptr += i;
318   len += i;                     /*type */
319
320   i = put_long (ptr, RPL_TK_BLOCK, out->block);
321   ptr += i;
322   len += i;
323
324   i = write_short (ptr, 0x2 + 0x2 + 0x9);
325   ptr += i;
326   len += i;
327   i = write_short (ptr, RPL_TK_ADDR);
328   ptr += i;
329   len += i;
330   i = write_long (ptr, out->addr.load);
331   ptr += i;
332   len += i;
333   i = write_long (ptr, out->addr.run);
334   ptr += i;
335   len += i;
336   i = write_char (ptr, out->addr.flags);
337   ptr += i;
338   len += i;
339
340   i = write_short (ptr, 0x2 + 0x2 + out->datalen);
341   ptr += i;
342   len += i;
343   i = write_short (ptr, RPL_TK_DATA);
344   ptr += i;
345   len += i;
346   bcopy (out->data, ptr, out->datalen);
347   ptr += out->datalen;
348   len += out->datalen;
349
350
351   ptr = buf;
352   write_short (ptr, len);       /*length */
353
354   send_llc_frame (n, RPL_SAP, RPL_SAP, dmac, buf, len);
355
356
357 }
358
359 void
360 rpl_send_packet (struct nit *n, unsigned char *d, struct rpl_packet *p)
361 {
362
363   switch (p->type)
364     {
365     case RPL_PK_FOUND:
366       send_found_frame (n, d, p);
367       break;
368     case RPL_PK_FILEDATA:
369       send_file_data_frame (n, d, p);
370       break;
371     default:
372       syslog (LOG_ERR, "rpl_send_packet: unknown packet type 0x%04x", p->type);
373     }
374 }
375
376 /* The llc code calls this whenever it gets a valid rpl packet */
377 void
378 rpl_packet_recvd (struct nit *n, unsigned char *pptr, int plen)
379 {
380
381   struct rpl_packet p;
382   int elen;
383
384   if (plen < 6)
385     return;
386
387   elen = ntohs (*(u16 *) pptr);
388
389   if (elen != plen)
390     {
391       syslog (LOG_ERR, "received lengths disagree %d vs %d", elen, plen);
392     }
393
394   if (elen > plen)
395     elen = plen;
396
397   pptr += 2;                    /*Length */
398   elen -= 2;
399
400   if (elen < 2)
401     return;
402   p.type = ntohs (*(u16 *) pptr);
403
404   pptr += 2;
405   elen -= 2;
406
407   p.flags = 0;
408
409   rpl_frag (&p, pptr, elen);    /*Analyse the packet */
410
411   rpl_packet_recvd_callback (n, &p);  /*Pass it up to the protocol layer */
412
413 }