FreeBSD/Linux Kernel Cross Reference
sys/ip/tripmedium.c
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
8 #include "ip.h"
9 #include "trip.h"
10
11 static void tripread(void *a);
12 static void tripbind(Ipifc *ifc, int argc, char **argv);
13 static void tripunbind(Ipifc *ifc);
14 static void tripbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
15 static void tripaddmulti(Ipifc *ifc, uchar*, uchar*);
16 static void tripremmulti(Ipifc *ifc, uchar*, uchar*);
17 static void tripaddroute(Ipifc *ifc, int, uchar*, uchar*, uchar*, int);
18 static void tripremroute(Ipifc *ifc, int, uchar*, uchar*);
19 static void tripares(Fs*, int, uchar*, uchar*, int, int);
20
21 Medium tripmedium =
22 {
23 .name= "trip",
24 .mintu= 20,
25 .maxtu= 64*1024,
26 .maclen= LCIMACSIZE,
27 .bind= tripbind,
28 .unbind= tripunbind,
29 .bwrite= tripbwrite,
30 .addmulti= tripaddmulti,
31 .remmulti= tripremmulti,
32 .addroute= tripaddroute,
33 .remroute= tripremroute,
34 .ares= tripares,
35 };
36
37 typedef struct Tripinfo Tripinfo;
38 struct Tripinfo
39 {
40 Fs* fs; /* my instance of the IP stack */
41 Ipifc* ifc; /* IP interface */
42 Card* dev;
43 Proc* readp; /* reading process */
44 Chan* mchan; /* Data channel */
45 };
46
47 /*
48 * called to bind an IP ifc to an ethernet device
49 * called with ifc qlock'd
50 */
51 static void
52 tripbind(Ipifc *ifc, int argc, char **argv)
53 {
54 int fd;
55 Chan *mchan;
56 Tripinfo *er;
57
58 if(argc < 2)
59 error(Ebadarg);
60
61 fd = kopen(argv[2], ORDWR);
62 if(fd < 0)
63 error("trip open failed");
64
65 mchan = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1);
66 kclose(fd);
67
68 if(devtab[mchan->type]->dc != 'T') {
69 cclose(mchan);
70 error(Enoport);
71 }
72
73 er = smalloc(sizeof(*er));
74 er->mchan = mchan;
75 er->ifc = ifc;
76 er->dev = tripsetifc(mchan, ifc);
77 er->fs = ifc->conv->p->f;
78
79 ifc->arg = er;
80
81 kproc("tripread", tripread, ifc);
82 }
83
84 /*
85 * called with ifc qlock'd
86 */
87 static void
88 tripunbind(Ipifc *ifc)
89 {
90 Tripinfo *er = ifc->arg;
91 /*
92 if(er->readp)
93 postnote(er->readp, 1, "unbind", 0);
94 */
95 tsleep(&up->sleep, return0, 0, 300);
96
97 if(er->mchan != nil)
98 cclose(er->mchan);
99
100 free(er);
101 }
102
103 /*
104 * called by ipoput with a single block to write
105 */
106 static void
107 tripbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
108 {
109 Tripinfo *er = ifc->arg;
110
111 /*
112 * Packet is rerouted at linecard
113 * so the gateway is ignored
114 */
115 USED(ip);
116 USED(version);
117
118 if(waserror()) {
119 print("tripwrite failed\n");
120 return;
121 }
122
123 devtab[er->mchan->type]->bwrite(er->mchan, bp, 0);
124 poperror();
125 ifc->out++;
126 }
127
128 /*
129 * process to read from the trip interface
130 */
131 static void
132 tripread(void *a)
133 {
134 Ipifc *ifc;
135 Block *bp;
136 Tripinfo *er;
137
138 ifc = a;
139 er = ifc->arg;
140 er->readp = up; /* hide identity under a rock for unbind */
141
142 for(;;) {
143 bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxtu, 0);
144 ifc->in++;
145 ipiput4(er->fs, ifc, bp);
146 }
147
148 pexit("hangup", 1);
149 }
150
151 static void
152 tripaddroute(Ipifc *ifc, int v, uchar *addr, uchar *mask, uchar *gate, int t)
153 {
154 int alen;
155 MTroute mtr;
156 Tripinfo *tinfo;
157
158 tinfo = ifc->arg;
159 if(!tinfo->dev->routing)
160 return;
161
162 /*
163 * Multicast addresses are handled on the linecard by
164 * the multicast port driver, so the route load is dumped.
165 * loaded by addmulti/remmulti for SBC routes
166 * joinmulti/leavemulti for inter LC
167 */
168 if(ipismulticast(addr))
169 return;
170
171 mtr.type = T_ROUTEADMIN;
172 if(v & Rv4) {
173 mtr.op = RTADD4;
174 alen = IPv4addrlen;
175 }
176 else {
177 mtr.op = RTADD6;
178 alen = IPaddrlen;
179 }
180 mtr.rtype = t;
181 memmove(mtr.addr, addr, alen);
182 memmove(mtr.mask, mask, alen);
183 memmove(mtr.gate, gate, alen);
184
185 i2osend(tinfo->dev, &mtr, sizeof(mtr));
186 }
187
188 static void
189 tripremroute(Ipifc *ifc, int v, uchar *addr, uchar *mask)
190 {
191 int alen;
192 MTroute mtr;
193 Tripinfo *tinfo;
194
195 tinfo = ifc->arg;
196 if(!tinfo->dev->routing)
197 return;
198
199 if(ipismulticast(addr))
200 return;
201
202 mtr.type = T_ROUTEADMIN;
203 if(v & Rv4) {
204 mtr.op = RTDEL4;
205 alen = IPv4addrlen;
206 }
207 else {
208 mtr.op = RTDEL6;
209 alen = IPaddrlen;
210 }
211 memmove(mtr.addr, addr, alen);
212 memmove(mtr.mask, mask, alen);
213
214 i2osend(tinfo->dev, &mtr, sizeof(mtr));
215 }
216
217 static void
218 tripxmitroute(Route *r, Routewalk *rw)
219 {
220 int nifc;
221 char t[5];
222 uchar a[IPaddrlen], m[IPaddrlen], g[IPaddrlen];
223
224 convroute(r, a, m, g, t, &nifc);
225 if(!(r->type & Rv4)) {
226 tripaddroute(rw->state, 0, a, m, g, r->type);
227 return;
228 }
229
230 tripaddroute(rw->state, Rv4, a+IPv4off, m+IPv4off, g+IPv4off, r->type);
231 }
232
233 static void
234 sendifcinfo(Ipifc *dest)
235 {
236 Conv **cp, **e;
237 Iplifc *l;
238 Ipifc *ifc;
239 MTifctl mtc;
240 Tripinfo *tinfo, *oinfo;
241 Proto *p;
242
243 tinfo = dest->arg;
244
245 /* Install interfaces */
246 p = tinfo->fs->ipifc;
247 e = &p->conv[p->nc];
248 for(cp = p->conv; cp < e; cp++) {
249
250 if(*cp == nil)
251 continue;
252
253 ifc = (Ipifc*)(*cp)->ptcl;
254 if(dest == ifc)
255 continue;
256
257 mtc.type = T_CTLIFADMIN;
258 mtc.maxtu = ifc->maxtu;
259 mtc.mintu = ifc->mintu;
260
261 mtc.port = 0;
262 if(ifc->m == &tripmedium) {
263 oinfo = ifc->arg;
264 mtc.port = oinfo->dev->bar[0].bar;
265 }
266
267 for(l = ifc->lifc; l != nil; l = l->next) {
268 if(isv4(l->local)) {
269 mtc.op = IFADD4;
270 memmove(mtc.addr, l->local+IPv4off, IPv4addrlen);
271 memmove(mtc.mask, l->mask+IPv4off, IPv4addrlen);
272 }
273 else {
274 mtc.op = IFADD6;
275 memmove(mtc.addr, l->local, sizeof(mtc.addr));
276 memmove(mtc.mask, l->mask, sizeof(mtc.mask));
277 }
278
279 i2osend(tinfo->dev, &mtc, sizeof(mtc));
280 }
281 }
282 }
283
284 void
285 tripsync(Ipifc *ifc)
286 {
287 Routewalk rw;
288
289 if(ifc == nil) {
290 print("tripsync: interface not bound\n");
291 return;
292 }
293
294 /* Mirror the route table into the lincard */
295 rw.o = 0;
296 rw.n = (1<<22);
297 rw.state = ifc;
298 rw.walk = tripxmitroute;
299
300 ipwalkroutes(ifc->conv->p->f, &rw);
301
302 /*
303 * Tell the linecard about interfaces that already
304 * exist elsewhere
305 */
306 sendifcinfo(ifc);
307 }
308
309 /* Tell a line card the SBC is interested in listening
310 * to a multicast address
311 */
312 static void
313 tripaddmulti(Ipifc *ifc, uchar *addr, uchar *ifca)
314 {
315 MTmultiears mt;
316 Tripinfo *tinfo;
317
318 /* print("tripaddmulti %I %I\n", addr, ifca); /**/
319
320 tinfo = ifc->arg;
321 if(!tinfo->dev->routing)
322 return;
323
324 mt.type = T_MULTIEAR;
325 mt.op = ADDMULTI;
326 memmove(mt.addr, addr, sizeof(mt.addr));
327 memmove(mt.ifca, ifca, sizeof(mt.ifca));
328
329 i2osend(tinfo->dev, &mt, sizeof(mt));
330 }
331
332 /* Tell a line card the SBC is no longer interested in listening
333 * to a multicast address
334 */
335 static void
336 tripremmulti(Ipifc *ifc, uchar *addr, uchar *ifca)
337 {
338 MTmultiears mt;
339 Tripinfo *tinfo;
340
341 tinfo = ifc->arg;
342 if(!tinfo->dev->routing)
343 return;
344
345 mt.type = T_MULTIEAR;
346 mt.op = REMMULTI;
347 memmove(mt.addr, addr, sizeof(mt.addr));
348 memmove(mt.ifca, ifca, sizeof(mt.ifca));
349
350 i2osend(tinfo->dev, &mt, sizeof(mt));
351 }
352
353 static void
354 tripares(Fs *fs, int vers, uchar *ip, uchar *mac, int l, int)
355 {
356 Route *r;
357 Ipifc *ifc;
358 MTaresenter ta;
359 Tripinfo *tinfo;
360 uchar v6ip[IPaddrlen];
361
362 if(vers == V4) {
363 r = v4lookup(fs, ip);
364 v4tov6(v6ip, ip);
365 ip = v6ip;
366 }
367 else
368 r = v6lookup(fs, ip);
369
370 if(r == nil) {
371 print("tripares: no route for entry\n");
372 return;
373 }
374
375 ifc = r->ifc;
376
377 tinfo = ifc->arg;
378 if(!tinfo->dev->routing)
379 return;
380
381 if(vers == V4) {
382 v4tov6(v6ip, ip);
383 ip = v6ip;
384 }
385
386 ta.type = T_ARESENTER;
387 ta.maclen = l;
388 memmove(ta.addr, ip, IPaddrlen);
389 memmove(ta.amac, mac, l);
390
391 i2osend(tinfo->dev, &ta, sizeof(ta));
392 }
393
394 void
395 tripmediumlink(void)
396 {
397 addipmedium(&tripmedium);
398 }
Cache object: 6acad5d2b763588f0a97c307ceb33c35
|