1 #ifdef RCSIDENT
2 static char rcsident[] = "$Header: raw_input.c,v 1.17 85/07/31 09:33:16 walsh Exp $";
3 #endif
4
5 #include "../h/param.h"
6 #include "../h/dir.h"
7 #include "../h/user.h"
8 #include "../machine/mtpr.h"
9 #include "../h/mbuf.h"
10 #include "../h/socket.h"
11 #include "../h/socketvar.h"
12
13 #include "../net/if.h"
14 #include "../net/netisr.h"
15 #include "../net/route.h"
16 #include "../net/raw_cb.h"
17
18 #include "../bbnnet/in.h"
19 #include "../bbnnet/net.h"
20 #include "../bbnnet/in_pcb.h"
21 #include "../bbnnet/in_var.h"
22 #include "../bbnnet/ip.h"
23 #include "../bbnnet/fsm.h"
24 #include "../bbnnet/tcp.h"
25 #include "../bbnnet/icmp.h"
26 #include "../bbnnet/udp.h"
27 #ifdef HMP
28 #include "../bbnnet/hmp.h"
29 #endif HMP
30 #include "../bbnnet/nopcb.h"
31
32 /*
33 * Sort INET packets for user(s). To get a packet, socket must match:
34 *
35 * raw_ip_proto
36 * domain (INET)
37 * protocol (TCP/UDP/ICMP)
38 * raw_ip_dst
39 * domain (INET)
40 * address, but not port, if connected(2)
41 * raw_ip_src
42 * domain (INET)
43 * address, but not port, if bound(2)
44 *
45 * Called from ip_input() for packets that were well-formed enough to get
46 * passed up to TCP/UDP/ICMP.
47 */
48 struct sockaddr_in raw_ip_dst =
49 {
50 AF_INET
51 } ;
52 struct sockaddr_in raw_ip_src =
53 {
54 AF_INET
55 } ;
56 struct sockproto raw_ip_proto =
57 {
58 PF_INET
59 } ;
60
61 raw_ip_input(m)
62 struct mbuf *m;
63 {
64 register struct ip *ip = mtod(m, struct ip *);
65
66 raw_ip_proto.sp_protocol = ip->ip_p;
67 raw_ip_dst.sin_addr.s_addr = ip->ip_dst.s_addr;
68 raw_ip_src.sin_addr.s_addr = ip->ip_src.s_addr;
69
70 raw_input (m, &raw_ip_proto, (struct sockaddr *)&raw_ip_src,
71 (struct sockaddr *)&raw_ip_dst);
72 }
73
74 /*
75 * Bad ip packets, which are taken care of via calls to ip_log() and netlog().
76 */
77 struct sockaddr_in netlog_dst =
78 {
79 AF_INET
80 } ;
81 struct sockaddr_in netlog_src =
82 {
83 AF_INET
84 } ;
85 struct sockproto netlog_proto =
86 {
87 PF_INET, NETLOG_PROTO
88 } ;
89
90 netlog(m)
91 struct mbuf *m;
92 {
93 raw_input (m, &netlog_proto, (struct sockaddr *)&netlog_src,
94 (struct sockaddr *)&netlog_dst);
95 }
96
97 #ifdef AF_TCPDEBUG
98 /*
99 * TCP debugging log
100 *
101 * Though the mbuf contains a copy of the tcpcb, and thus a pointer to the
102 * inpcb, kernel can't do address sorting since this may point within a freed
103 * (and perhaps now recycled) mbuf. Remember that this logging is done after
104 * state changes (closing).
105 */
106 struct sockaddr_in tcpdebug_dst =
107 {
108 AF_TCPDEBUG
109 } ;
110 struct sockaddr_in tcpdebug_src =
111 {
112 AF_TCPDEBUG
113 } ;
114 struct sockproto tcpdebug_proto =
115 {
116 PF_TCPDEBUG, 0
117 } ;
118
119 tcpdebuglog(m)
120 struct mbuf *m;
121 {
122 raw_input (m, &tcpdebug_proto, (struct sockaddr *)&tcpdebug_src,
123 (struct sockaddr *)&tcpdebug_dst);
124 }
125 #else
126 tcpdebuglog(m)
127 struct mbuf *m;
128 {
129 m_freem(m);
130 }
131 #endif
132
133 #ifdef AF_RDPDEBUG
134 struct sockaddr_in rdpdebug_dst =
135 {
136 AF_RDPDEBUG
137 } ;
138 struct sockaddr_in rdpdebug_src =
139 {
140 AF_RDPDEBUG
141 } ;
142 struct sockproto rdpdebug_proto =
143 {
144 PF_RDPDEBUG, 0
145 } ;
146
147 rdpdebuglog(m)
148 struct mbuf *m;
149 {
150 raw_input (m, &rdpdebug_proto, (struct sockaddr *)&rdpdebug_src,
151 (struct sockaddr *)&rdpdebug_dst);
152 }
153 #else
154 rdpdebuglog(m)
155 struct mbuf *m;
156 {
157 m_freem(m);
158 }
159 #endif
160
161
m_bpullup(m0,len)162 struct mbuf *m_bpullup(m0, len)
163 struct mbuf *m0;
164 int len;
165 {
166 register struct mbuf *m, *n;
167 unsigned count;
168
169 n = m0;
170 if (len > MLEN)
171 {
172 m_freem(n);
173 return ((struct mbuf *) NULL);
174 }
175 #ifdef MBUF_DEBUG
176 m = m_get(M_DONTWAIT, n->m_type);
177 #else
178 MGET(m, M_DONTWAIT, n->m_type);
179 #endif
180 if (m == 0)
181 {
182 m_freem(n);
183 return ((struct mbuf *) NULL);
184 }
185 m->m_len = 0;
186 m->m_off = MMAXOFF - len; /* -- difference from m_pullup -- */
187 do
188 {
189 count = MIN(len, n->m_len);
190 bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, count);
191 len -= count;
192 m->m_len += count;
193 n->m_off += count;
194 n->m_len -= count;
195 if (n->m_len)
196 break;
197 n = m_free(n);
198 }
199 while (n);
200
201 if (len)
202 {
203 (void) m_free(m);
204 m_freem(n);
205 return ((struct mbuf *) NULL);
206 }
207 m->m_next = n;
208 return (m);
209 }
210
211 /*
212 * output function called from net/raw_usrreq
213 */
214
215 /* ARGSUSED */
216 raw_ip_output (m0, so)
217 struct mbuf *m0;
218 struct socket *so;
219 {
220 register struct mbuf *m;
221 register struct ip *ip;
222 register int len;
223 int retval;
224
225 /*
226 * verify length of datagram, get IP header at end of mbuf so can
227 * prepend local net header.
228 */
229 len = 0;
230 for (m = m0 ; m ; m = m->m_next)
231 len += m->m_len;
232 if (len < sizeof(struct ip))
233 {
234 m_freem(m0);
235 return(EMSGSIZE); /* ### */
236 }
237 if ((m = m_bpullup(m0, sizeof(struct ip))) == NULL)
238 return (ENOBUFS);
239 ip = mtod(m, struct ip *);
240 if ((ntohs((u_short)ip->ip_len) != len) ||
241 ((ip->ip_hl << IP_HLSHIFT) > len))
242 {
243 m_freem(m);
244 return(EMSGSIZE); /* ### */
245 }
246
247 #ifdef notdef
248 /* have to be super-user anyway to do this.
249 * Cronus wants to be able to forward broadcast UDP packets.
250 */
251
252 /*
253 * verify that addresses are valid
254 */
255 if (in_broadcast(ip->ip_src) || (in_iawithaddr(ip->ip_src, TRUE) == 0))
256 #else
257 if (in_broadcast(ip->ip_src))
258 #endif
259 {
260 m_freem(m);
261 return (EADDRNOTAVAIL);
262 }
263
264 NOPCB_IPSEND (m, len, TRUE, retval);
265 return (retval);
266 }
267
268
269
270 /*
271 * Send out an icmp packet. Use the user's ICMP header, and our own IP
272 * header.
273 */
274 /* ARGSUSED */
275 raw_icmp_output (m0, so)
276 struct mbuf *m0;
277 struct socket *so;
278 {
279 register struct mbuf *m;
280 register struct icmp *p;
281 register struct ip *ip;
282 register struct rawcb *rcb;
283 int len;
284 int retval;
285
286 rcb = sotorawcb(so);
287 if (!(rcb->rcb_flags & RAW_FADDR))
288 {
289 m_freem(m0);
290 return(EDESTADDRREQ);
291 }
292
293 /*
294 * find length of datagram
295 */
296 len = 0;
297 for (m = m0 ; m ; m = m->m_next)
298 len += m->m_len;
299 if (len < ICMPSIZE)
300 {
301 m_freem(m0);
302 return (EMSGSIZE); /* ### */
303 }
304
305 /*
306 * Pull up user's ICMP header so we can prepend IP header later.
307 */
308 if ((m = m_bpullup(m0, ICMPSIZE)) == NULL)
309 return (ENOBUFS);
310
311 /*
312 * "Verify" ICMP header. Accept user's type and code.
313 */
314 p = mtod(m, struct icmp *);
315
316 /*
317 * Use our own checksum, though. It'll be at least as fast as the
318 * user's and we'll have to use those CPU cycles sometime.
319 */
320 p->ic_sum = 0;
321 p->ic_sum = in_cksum(m, len);
322
323 /*
324 * Fill in IP header and send it
325 */
326 m->m_off -= sizeof(struct ip);
327 m->m_len += sizeof(struct ip);
328 ip = mtod(m, struct ip *);
329 ip->ip_p = IPPROTO_ICMP;
330 ip->ip_tos = 0;
331 ip->ip_dst.s_addr =
332 ((struct sockaddr_in *) &rcb->rcb_faddr)->sin_addr.s_addr;
333
334 if (rcb->rcb_flags & RAW_LADDR)
335 {
336 ip->ip_src.s_addr =
337 ((struct sockaddr_in *) &rcb->rcb_laddr)->sin_addr.s_addr;
338 }
339 else
340 {
341 /*
342 * We may examine the routing tables twice.
343 * perhaps if this gets used a lot, it can be changed.
344 */
345 struct route r;
346 struct rtentry *rt;
347
348 bzero ((caddr_t) &r, sizeof(r));
349 ((struct sockaddr_in *) (&r.ro_dst)) ->sin_family = AF_INET;
350 ((struct sockaddr_in *) (&r.ro_dst)) ->sin_addr.s_addr =
351 ip->ip_dst.s_addr;
352 rtalloc(&r);
353 if (rt = r.ro_rt)
354 {
355 ip->ip_src = IA_INADDR(in_iafromif(rt->rt_ifp));
356 rtfree (rt);
357 }
358 else
359 {
360 m_freem(m);
361 return (ENETUNREACH);
362 }
363 }
364
365 NOPCB_IPSEND (m, len, FALSE, retval);
366 return (retval);
367 }
368
369 #ifdef NSIP
370 /*
371 * Generate IP header and pass packet to ip_output.
372 * Tack on options user may have setup with control call.
373 */
374 rip_output(m0, so)
375 struct mbuf *m0;
376 struct socket *so;
377 {
378 register struct mbuf *m;
379
380 /*
381 * get an mbuf for IP header.
382 */
383 m = m_get(M_DONTWAIT, MT_HEADER);
384 if (m == NULL)
385 {
386 m_freem(m0);
387 return (ENOBUFS);
388 }
389
390 /*
391 * Fill in IP header as needed.
392 */
393 m->m_off = MMAXOFF - sizeof(struct ip);
394 m->m_len = sizeof(struct ip);
395 m->m_next = m0;
396 {
397 register struct ip *ip;
398 register struct rawcb *rcb = sotorawcb(so);
399
400 ip = mtod(m, struct ip *);
401 ip->ip_p = rcb->rcb_proto.sp_protocol;
402 ip->ip_tos = 0;
403 ip->ip_dst.s_addr =
404 ((struct sockaddr_in *) &rcb->rcb_faddr)->sin_addr.s_addr;
405 if (rcb->rcb_flags & RAW_LADDR)
406 ip->ip_src.s_addr =
407 ((struct sockaddr_in *) &rcb->rcb_laddr)->sin_addr.s_addr;
408 else
409 ip->ip_src.s_addr = 0;
410 }
411
412 {
413 register int retval;
414 register int len;
415
416 /*
417 * Calculate data length
418 */
419 len = 0;
420 while (m0)
421 {
422 len += m0->m_len;
423 m0 = m0->m_next;
424 }
425
426
427 NOPCB_IPSEND (m, len, FALSE, retval);
428 return (retval);
429 }
430 }
431 #endif
432
433 /*
434 * The UDP header is so small and simple, the user should either:
435 * 1. go all the way and use a raw IP socket
436 * or 2. use send(2) type system calls.
437 */
438 /* ARGSUSED */
439 raw_udp_output (m0, so)
440 struct mbuf *m0;
441 struct socket *so;
442 {
443 m_freem(m0);
444 return (EOPNOTSUPP);
445 }
446
447 /*
448 * TCP requires a lot of state information. Sure we could try to verify the
449 * user's header and pass it on to ip, but unless debugging a new version
450 * in user code with a different protocol number, probably shouldn't ship
451 * out tcp packets, since we'll get packets in reply that might screw us up.
452 *
453 * And how does the sending of a single tcp packet make sense?
454 */
455 /* ARGSUSED */
456 raw_tcp_output (m0, so)
457 struct mbuf *m0;
458 struct socket *so;
459 {
460 m_freem(m0);
461 return (EOPNOTSUPP);
462 }
463
464 #ifdef RDP
465 /*
466 * ditto TCP for RDP
467 */
468 /* ARGSUSED */
469 raw_rdp_output (m0, so)
470 struct mbuf *m0;
471 struct socket *so;
472 {
473 m_freem(m0);
474 return(EOPNOTSUPP);
475 }
476 #endif
477
478 /*
479 * use the user level stuff to send -- much simpler
480 */
481
482 #ifdef HMP
483 /* ARGSUSED */
484 raw_hmp_output (m0, so)
485 struct mbuf *m0;
486 struct socket *so;
487 {
488 m_freem(m0);
489 return(EOPNOTSUPP);
490 }
491 #endif
492