|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "../port/error.h"
7: #include "arp.h"
8: #include "../port/ipdat.h"
9:
10: #include "devtab.h"
11:
12: /*
13: * All ip numbers and masks are stored as ulongs.
14: * All interfaces to this code uses the standard byte
15: * string representation.
16: */
17:
18: typedef struct Iproute Iproute;
19: typedef struct Iprtab Iprtab;
20:
21: enum
22: {
23: Nroutes= 1024,
24: };
25:
26: /*
27: * routes
28: */
29: struct Iproute {
30: ulong dst;
31: ulong gate;
32: ulong mask;
33: Iproute *next;
34: int inuse;
35: };
36: struct Iprtab {
37: Lock;
38: int n; /* number of valid routes */
39: Iproute *first; /* list of valid routes */
40: Iproute r[Nroutes]; /* all routes */
41: };
42: Iprtab iprtab;
43:
44: /*
45: * The chosen route is the one obeys the constraint
46: * r->mask & dst == r->dst
47: *
48: * If there are several matches, the one whose mask has the most
49: * leading ones (and hence is the most specific) wins. This is
50: * forced by storing the routes in decreasing number of ones order
51: * and returning the first match. The default gateway has no ones
52: * in the mask and is thus the last matched.
53: */
54: Ipdevice*
55: iproute(uchar *dst, uchar *gate)
56: {
57: Iproute *r;
58: Ipdevice *p;
59: ulong udst;
60:
61: udst = nhgetl(dst);
62: for(p = ipd; p < &ipd[Nipd]; p++){
63: if(p->q == 0)
64: continue;
65: if((udst&p->Mynetmask) == p->Remip){
66: memmove(gate, dst, 4);
67: return p;
68: }
69: }
70:
71: /*
72: * first check routes
73: */
74: for(r = iprtab.first; r; r = r->next){
75: if((r->mask&udst) == r->dst){
76: hnputl(gate, r->gate);
77: for(p = ipd; p < &ipd[Nipd]; p++){
78: if(p->q == 0)
79: break;
80: if((r->gate&p->Mynetmask) == p->Remip)
81: return p;
82: }
83: return ipd;
84: }
85: }
86:
87: /*
88: * else just return the same address and first interface
89: */
90: memmove(gate, dst, 4);
91: return ipd;
92: }
93:
94: /*
95: * Add a route, create a mask if the first mask is 0.
96: *
97: * All routes are stored sorted by the length of leading
98: * ones in the mask.
99: *
100: * NOTE: A default route has an all zeroes mask and dst.
101: */
102: void
103: ipaddroute(ulong dst, ulong mask, ulong gate)
104: {
105: Iproute *r, *e, *free;
106:
107: /*
108: * filter out impossible requests
109: */
110: if((dst&mask) != dst)
111: error(Enetaddr);
112:
113: /*
114: * see if we already have a route for
115: * the destination
116: */
117: lock(&iprtab);
118: free = 0;
119: for(r = iprtab.r; r < &iprtab.r[Nroutes]; r++){
120: if(r->inuse == 0){
121: free = r;
122: continue;
123: }
124: if(dst==r->dst && mask==r->mask){
125: r->gate = gate;
126: unlock(&iprtab);
127: return;
128: }
129: }
130: if(free == 0){
131: unlock(&iprtab);
132: exhausted("routes");
133: }
134:
135: /*
136: * add the new route in sorted order
137: */
138: free->dst = dst;
139: free->mask = mask;
140: free->gate = gate;
141: free->inuse = 1;
142: for(r = e = iprtab.first; r; r = r->next){
143: if(mask > r->mask)
144: break;
145: e = r;
146: }
147: free->next = r;
148: if(r == iprtab.first)
149: iprtab.first = free;
150: else
151: e->next = free;
152: iprtab.n++;
153: unlock(&iprtab);
154: }
155:
156: /*
157: * remove a route
158: */
159: void
160: ipremroute(ulong dst, ulong mask)
161: {
162: Iproute *r, *e;
163:
164: lock(&iprtab);
165: for(r = e = iprtab.first; r; r = r->next){
166: if(dst==r->dst && (mask == 0 || mask==r->mask)){
167: if(r == iprtab.first)
168: iprtab.first = r->next;
169: else
170: e->next = r->next;
171: r->inuse = 0;
172: iprtab.n--;
173: break;
174: }
175: e = r;
176: }
177: unlock(&iprtab);
178: }
179:
180: /*
181: * remove all routes
182: */
183: void
184: ipflushroute(void)
185: {
186: Iproute *r;
187:
188: lock(&iprtab);
189: for(r = iprtab.first; r; r = r->next)
190: r->inuse = 0;
191: iprtab.first = 0;
192: iprtab.n = 0;
193: unlock(&iprtab);
194: }
195:
196: /*
197: * device interface
198: */
199: enum{
200: Qdir,
201: Qdata,
202: Qipifc,
203: };
204: Dirtab iproutetab[]={
205: "iproute", {Qdata}, 0, 0666,
206: "ipifc", {Qipifc}, 0, 0666,
207: };
208: #define Niproutetab (sizeof(iproutetab)/sizeof(Dirtab))
209:
210: void
211: iproutereset(void)
212: {
213: }
214:
215: void
216: iprouteinit(void)
217: {
218: }
219:
220: Chan *
221: iprouteattach(char *spec)
222: {
223: return devattach('P', spec);
224: }
225:
226: Chan *
227: iprouteclone(Chan *c, Chan *nc)
228: {
229: return devclone(c, nc);
230: }
231:
232: int
233: iproutewalk(Chan *c, char *name)
234: {
235: return devwalk(c, name, iproutetab, (long)Niproutetab, devgen);
236: }
237:
238: void
239: iproutestat(Chan *c, char *db)
240: {
241: devstat(c, db, iproutetab, (long)Niproutetab, devgen);
242: }
243:
244: Chan *
245: iprouteopen(Chan *c, int omode)
246: {
247: if(c->qid.path == CHDIR){
248: if(omode != OREAD)
249: error(Eperm);
250: }
251: c->mode = openmode(omode);
252: c->flag |= COPEN;
253: c->offset = 0;
254: return c;
255: }
256:
257: void
258: iproutecreate(Chan *c, char *name, int omode, ulong perm)
259: {
260: USED(c, name, omode, perm);
261: error(Eperm);
262: }
263:
264: void
265: iprouteremove(Chan *c)
266: {
267: USED(c);
268: error(Eperm);
269: }
270:
271: void
272: iproutewstat(Chan *c, char *dp)
273: {
274: USED(c, dp);
275: error(Eperm);
276: }
277:
278: void
279: iprouteclose(Chan *c)
280: {
281: USED(c);
282: }
283:
284: /* sprint an ip address right justified into a 16 char field */
285: char*
286: ipformat(char *to, ulong ip)
287: {
288: uchar hip[4];
289: char buf[17];
290: int n;
291:
292: hnputl(hip, ip);
293: n = sprint(buf, "%d.%d.%d.%d", hip[0], hip[1], hip[2], hip[3]);
294: memset(to, ' ', 16 - n);
295: memmove(to+16-n, buf, n);
296: to[16] = 0;
297: return to;
298: }
299:
300: long
301: iprouteread(Chan *c, void *a, long n, ulong offset)
302: {
303: Iproute *r;
304: Ipdevice *p;
305: char *va = a;
306: char *e;
307: int part, bytes, size;
308: char dst[17], mask[17], gate[17];
309: char buf[128];
310:
311: switch((int)(c->qid.path&~CHDIR)){
312: case Qdir:
313: return devdirread(c, a, n, iproutetab, Niproutetab, devgen);
314: case Qdata:
315: lock(&iprtab);
316: bytes = 0;
317: e = va + n;
318: for(r = iprtab.first; r && va < e; r = r->next){
319: size = sprint(buf, "%s & %s -> %s\n", ipformat(dst, r->dst),
320: ipformat(mask, r->mask), ipformat(gate, r->gate));
321: if(bytes + size <= offset){
322: bytes += size;
323: continue;
324: }
325:
326: if(va == a){
327: part = offset - bytes;
328: size -= part;
329: } else
330: part = 0;
331: if(size > n)
332: size = n;
333:
334: memmove(va, buf + part, size);
335: va += size;
336: }
337: unlock(&iprtab);
338: n = va - (char*)a;
339: break;
340: case Qipifc:
341: bytes = 0;
342: e = va + n;
343: for(p = ipd; p < &ipd[Nipd] && va < e; p++){
344: if(p->q == 0)
345: continue;
346: size = sprint(buf, " #%C%d %5d %s %s %s\n",
347: devchar[p->type], p->dev, p->maxmtu,
348: ipformat(dst, p->Myip[0]),
349: ipformat(mask, p->Mynetmask),
350: ipformat(gate, p->Remip));
351: if(bytes + size <= offset){
352: bytes += size;
353: continue;
354: }
355:
356: if(va == a){
357: part = offset - bytes;
358: size -= part;
359: } else
360: part = 0;
361: if(size > n)
362: size = n;
363:
364: memmove(va, buf + part, size);
365: va += size;
366: }
367: n = va - (char*)a;
368: break;
369: default:
370: n=0;
371: break;
372: }
373: return n;
374: }
375:
376: long
377: iproutewrite(Chan *c, char *a, long n, ulong offset)
378: {
379: char buf[128];
380: char *field[4];
381: Ipaddr mask, dst, gate;
382: int m;
383:
384: USED(offset);
385:
386: switch((int)(c->qid.path&~CHDIR)){
387: case Qdata:
388: strncpy(buf, a, sizeof buf);
389: m = getfields(buf, field, 4, " ");
390:
391: if(strncmp(field[0], "flush", 5) == 0)
392: ipflushroute();
393: else if(strncmp(field[0], "add", 3) == 0){
394: switch(m){
395: case 4:
396: dst = ipparse(field[1]);
397: mask = ipparse(field[2]);
398: gate = ipparse(field[3]);
399: ipaddroute(dst, mask, gate);
400: break;
401: case 3:
402: dst = ipparse(field[1]);
403: gate = ipparse(field[2]);
404: ipaddroute(dst, classmask[dst>>30], gate);
405: break;
406: default:
407: error(Ebadarg);
408: }
409: } else if(strncmp(field[0], "delete", 6) == 0){
410: switch(m){
411: case 3:
412: dst = ipparse(field[1]);
413: mask = ipparse(field[2]);
414: ipremroute(dst, mask);
415: break;
416: case 2:
417: dst = ipparse(field[1]);
418: ipremroute(dst, 0);
419: break;
420: default:
421: error(Ebadarg);
422: }
423: }
424: else
425: error(Ebadctl);
426: break;
427: default:
428: error(Ebadusefd);
429: }
430: return n;
431: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.