Commit | Line | Data |
---|---|---|
17efd7fe MK |
1 | #ifdef RCSIDENT |
2 | static char rcsident[] = "$Header: udp.c,v 1.18 85/07/31 09:44:10 walsh Exp $"; | |
3 | #endif | |
4 | ||
5 | ||
6 | #include "../h/param.h" | |
7 | #include "../h/systm.h" | |
8 | #include "../h/dir.h" | |
9 | #include "../h/user.h" | |
10 | #include "../h/mbuf.h" | |
11 | #include "../h/socket.h" | |
12 | #include "../h/socketvar.h" | |
13 | #include "../h/syslog.h" | |
14 | ||
15 | #include "../net/if.h" | |
16 | #include "../net/route.h" | |
17 | ||
18 | #include "../bbnnet/in.h" | |
19 | #include "../bbnnet/in_var.h" | |
20 | #include "../bbnnet/net.h" | |
21 | #include "../bbnnet/ip.h" | |
22 | #include "../bbnnet/udp.h" | |
23 | #include "../bbnnet/in_pcb.h" | |
24 | #include "../bbnnet/icmp.h" | |
25 | #ifdef HMPTRAPS | |
26 | #include "../bbnnet/hmp_traps.h" | |
27 | #endif | |
28 | ||
29 | #ifdef RCSIDENT | |
30 | static char rcsudphdr[] = RCSUDPHDR; | |
31 | #endif | |
32 | ||
33 | extern int nosum; | |
34 | ||
35 | struct inpcb udp; | |
36 | struct udp_stat udpstat; | |
37 | ||
38 | /* | |
39 | * Process incoming udp messages. Called directly from ip_input. | |
40 | * User sees udp header with pseudo-header which overlays ip header | |
41 | * (defined in udp.h). | |
42 | */ | |
43 | udp_input(mp) | |
44 | register struct mbuf *mp; | |
45 | { | |
46 | register struct udp *p; | |
47 | register struct inpcb *inp; | |
48 | register u_short i, j, ulen; | |
49 | ||
50 | udpstat.u_total ++; | |
51 | /* | |
52 | * see ip_input() | |
53 | */ | |
54 | if ((mp->m_off > MMAXOFF) || (mp->m_len < sizeof(struct udp))) | |
55 | { | |
56 | if ((mp = m_pullup(mp, sizeof(struct udp))) == NULL) | |
57 | { | |
58 | udpstat.u_tooshort ++; | |
59 | return; | |
60 | } | |
61 | } | |
62 | ||
63 | p = mtod(mp, struct udp *); | |
64 | ulen = ((struct ip *) p) ->ip_len; /* ip_input() set to amt IP data */ | |
65 | mp->m_off += sizeof p->u_x; | |
66 | mp->m_len -= sizeof p->u_x; | |
67 | p->u_x1 = 0; | |
68 | ||
69 | if (ntohs(p->u_len) != ulen) | |
70 | { | |
71 | /* | |
72 | * u_ilen overlays IP checksum, which is now zero. | |
73 | * ulen is the actual number of bytes we got on input | |
74 | * from IP; u_len is what UDP says we should have | |
75 | * (sizeof(udp_specific) + datalen) | |
76 | */ | |
1969a567 | 77 | log(LOG_WARNING, "UDP len %d, but got %d\n", ntohs(p->u_len), ulen); |
17efd7fe MK |
78 | netlog (mp); |
79 | return; | |
80 | } | |
81 | p->u_ilen = p->u_len; | |
82 | ||
83 | /* | |
84 | * Do checksum calculation. Assumes pseudo-header passed up from | |
85 | * IP level and finished above. | |
86 | * Zero checksum on send means no checksum was generated. | |
87 | */ | |
88 | if ((i = p->u_sum) != 0) | |
89 | { | |
90 | p->u_sum = 0; | |
91 | j = (u_short) in_cksum(mp, (int) (ulen + UDPCKSIZE)); | |
92 | /* | |
93 | * Remember that zero is special, and compensate for this. | |
94 | */ | |
95 | if (j == 0) | |
96 | j = (~j); | |
97 | if (i != j) | |
98 | { | |
99 | udpstat.u_badsum++; | |
100 | if (! nosum) | |
101 | { | |
102 | #ifdef HMPTRAPS | |
103 | /* hmp_trap(T_UDP_CKSUM, (caddr_t)0,0); */ | |
104 | #endif | |
105 | inet_cksum_err ("udp", (struct ip *) p, (u_long) i, (u_long) j); | |
106 | netlog(mp); | |
107 | return; | |
108 | } | |
109 | } | |
110 | } | |
111 | ||
112 | inp = in_pcblookup(&udp, p->u_s.s_addr, (u_short)0, | |
113 | p->u_d.s_addr, p->u_dst, TRUE); | |
114 | ||
115 | /* if a user is found, queue the data, otherwise drop it */ | |
116 | ||
117 | if (inp != NULL) | |
118 | { | |
119 | struct sockaddr_in udpsock; | |
120 | struct sockbuf *sorcv; | |
121 | ||
122 | /* | |
123 | * throw away entire IP and UDP leaders. | |
124 | * user gets address separately. | |
125 | */ | |
126 | mp->m_off += sizeof (struct udp) - sizeof (p->u_x); | |
127 | mp->m_len -= sizeof (struct udp) - sizeof (p->u_x); | |
128 | ||
129 | udpsock.sin_family = AF_INET; | |
130 | udpsock.sin_port = p->u_src; | |
131 | udpsock.sin_addr = p->u_s; | |
132 | udpsock.sin_zero[0] = udpsock.sin_zero[1] = 0; | |
133 | ||
134 | sorcv = &inp->inp_socket->so_rcv; | |
135 | ||
136 | if (! sbappendaddr(sorcv, (struct sockaddr *)&udpsock, mp, | |
137 | (struct mbuf *) NULL)) | |
138 | { | |
139 | m_freem(mp); | |
140 | if ((ulen - UDPSIZE + sizeof(struct sockaddr)) > sbspace(sorcv)) | |
141 | udpstat.u_sonospace ++; | |
142 | else | |
143 | udpstat.u_nobuf ++; | |
144 | } | |
145 | else | |
146 | sorwakeup(inp->inp_socket); | |
147 | } | |
148 | else | |
149 | { | |
150 | /* | |
151 | * No one wants this packet. | |
152 | */ | |
153 | if (!in_broadcast(p->u_s) && !in_broadcast(p->u_d)) | |
154 | /* | |
155 | * Don't bother everyone on the net. Someone else may | |
156 | * provide the service (port). | |
157 | */ | |
158 | ic_errmsg (icmp_addr((struct ip *) p), p->u_s, | |
159 | ICMP_UNRCH, ICMP_UNRCH_PORT, 0, | |
160 | sizeof(struct ip) + ICMP_ERRLEN, (char *) p); | |
161 | ||
162 | udpstat.u_drops++; | |
163 | m_freem(mp); | |
164 | } | |
165 | } | |
166 | ||
167 | /* | |
168 | * Output a udp message. Called from udp_usrreq(). | |
169 | */ | |
170 | udp_output(inp, mp) | |
171 | struct inpcb *inp; | |
172 | register struct mbuf *mp; | |
173 | { | |
174 | register struct udp *p; | |
175 | register struct mbuf *m; | |
176 | register int len; | |
177 | ||
178 | len = 0; | |
179 | for (m = mp; m; m = m->m_next) | |
180 | len += m->m_len; | |
181 | ||
182 | /* | |
183 | * find a place to put the IP/UDP headers. | |
184 | */ | |
185 | m = m_get(M_WAIT, MT_HEADER); | |
186 | if (m == 0) | |
187 | { | |
188 | m_freem(mp); | |
189 | return (ENOBUFS); | |
190 | } | |
191 | m->m_next = mp; | |
192 | mp = m; | |
193 | ||
194 | /* | |
195 | * Compose header in first mbuf. Get addresses and ports | |
196 | * from ucb, add in pseudo-header fields for checksum. | |
197 | * Ensure header is aligned for memory access speed... | |
198 | */ | |
199 | mp->m_off = (MMAXOFF - sizeof(struct udp)) & ~(sizeof(long) -1); | |
200 | mp->m_len = sizeof(struct udp); | |
201 | p = mtod(mp, struct udp *); | |
202 | ||
203 | /* stuff UDP fields */ | |
204 | p->u_src = inp->inp_lport; | |
205 | p->u_dst = inp->inp_fport; | |
206 | p->u_len = htons((u_short)len+UDPSIZE); | |
207 | ||
208 | /* and "IP" fields */ | |
209 | ((struct ip *) p)->ip_tos = 0; /* for ip_send() */ | |
210 | p->u_x1 = 0; | |
211 | p->u_pr = IPPROTO_UDP; | |
212 | p->u_ilen = p->u_len; | |
213 | p->u_s = inp->inp_laddr; | |
214 | p->u_d = inp->inp_faddr; | |
215 | ||
216 | /* Do checksum. Include pseudo header. */ | |
217 | mp->m_off += sizeof p->u_x; | |
218 | mp->m_len -= sizeof p->u_x; | |
219 | p->u_sum = 0; | |
220 | p->u_sum = in_cksum(mp, len + sizeof(struct udp) - sizeof p->u_x); | |
221 | if (p->u_sum == 0) | |
222 | /* Zero is reserved for unsummed packets */ | |
223 | p->u_sum = (~ p->u_sum); | |
224 | mp->m_off -= sizeof p->u_x; | |
225 | mp->m_len += sizeof p->u_x; | |
226 | ||
227 | /* | |
228 | * Now send the packet via IP. | |
229 | */ | |
230 | return(ip_send(inp, mp, len+UDPSIZE, FALSE)); | |
231 | } |