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