FreeBSD/Linux Kernel Cross Reference
sys/netnatm/natm.c
1 /* $NetBSD: natm.c,v 1.16 2008/05/22 00:59:19 dyoung Exp $ */
2
3 /*
4 *
5 * Copyright (c) 1996 Charles D. Cranor and Washington University.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles D. Cranor and
19 * Washington University.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * natm.c: native mode ATM access (both aal0 and aal5).
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: natm.c,v 1.16 2008/05/22 00:59:19 dyoung Exp $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/domain.h>
46 #include <sys/ioctl.h>
47 #include <sys/proc.h>
48 #include <sys/protosw.h>
49 #include <sys/mbuf.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52
53 #include <net/if.h>
54 #include <net/if_atm.h>
55 #include <net/netisr.h>
56 #include <net/radix.h>
57 #include <net/route.h>
58
59 #include <netinet/in.h>
60
61 #include <netnatm/natm.h>
62
63 u_long natm5_sendspace = 16*1024;
64 u_long natm5_recvspace = 16*1024;
65
66 u_long natm0_sendspace = 16*1024;
67 u_long natm0_recvspace = 16*1024;
68
69 /*
70 * user requests
71 */
72
73 #if defined(__NetBSD__)
74 int natm_usrreq(so, req, m, nam, control, l)
75 #elif defined(__OpenBSD__)
76 int natm_usrreq(so, req, m, nam, control, p)
77 #elif defined(__FreeBSD__)
78 int natm_usrreq(so, req, m, nam, control)
79 #endif
80
81 struct socket *so;
82 int req;
83 struct mbuf *m, *nam, *control;
84 #if defined(__NetBSD__)
85 struct lwp *l;
86 #elif deifned(__OpenBSD__)
87 struct proc *p;
88 #endif
89
90 {
91 int error = 0, s, s2;
92 struct natmpcb *npcb;
93 struct sockaddr_natm *snatm;
94 struct atm_pseudoioctl api;
95 struct atm_pseudohdr *aph;
96 struct atm_rawioctl ario;
97 struct ifnet *ifp;
98 int proto = so->so_proto->pr_protocol;
99
100 s = SPLSOFTNET();
101
102 npcb = (struct natmpcb *) so->so_pcb;
103
104 if (npcb == NULL && req != PRU_ATTACH) {
105 error = EINVAL;
106 goto done;
107 }
108
109
110 switch (req) {
111 case PRU_ATTACH: /* attach protocol to up */
112
113 if (npcb) {
114 error = EISCONN;
115 break;
116 }
117
118 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
119 if (proto == PROTO_NATMAAL5)
120 error = soreserve(so, natm5_sendspace, natm5_recvspace);
121 else
122 error = soreserve(so, natm0_sendspace, natm0_recvspace);
123 if (error)
124 break;
125 }
126
127 so->so_pcb = (void *) (npcb = npcb_alloc(M_WAITOK));
128 npcb->npcb_socket = so;
129
130 break;
131
132 case PRU_DETACH: /* detach protocol from up */
133
134 /*
135 * we turn on 'drain' *before* we sofree.
136 */
137
138 npcb_free(npcb, NPCB_DESTROY); /* drain */
139 so->so_pcb = NULL;
140 /* sofree drops the lock */
141 sofree(so);
142 mutex_enter(softnet_lock);
143
144 break;
145
146 case PRU_CONNECT: /* establish connection to peer */
147
148 /*
149 * validate nam and npcb
150 */
151
152 if (nam->m_len != sizeof(*snatm)) {
153 error = EINVAL;
154 break;
155 }
156 snatm = mtod(nam, struct sockaddr_natm *);
157 if (snatm->snatm_len != sizeof(*snatm) ||
158 (npcb->npcb_flags & NPCB_FREE) == 0) {
159 error = EINVAL;
160 break;
161 }
162 if (snatm->snatm_family != AF_NATM) {
163 error = EAFNOSUPPORT;
164 break;
165 }
166
167 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
168 since ifunit() uses strcmp */
169
170 /*
171 * convert interface string to ifp, validate.
172 */
173
174 ifp = ifunit(snatm->snatm_if);
175 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
176 error = ENXIO;
177 break;
178 }
179 if (ifp->if_output != atm_output) {
180 error = EAFNOSUPPORT;
181 break;
182 }
183
184
185 /*
186 * register us with the NATM PCB layer
187 */
188
189 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
190 error = EADDRINUSE;
191 break;
192 }
193
194 /*
195 * enable rx
196 */
197
198 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
199 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
200 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
201 api.rxhand = npcb;
202 s2 = splnet();
203 if (ifp->if_ioctl == NULL || ifp->if_ioctl(ifp, SIOCATMENA, &api) != 0) {
204 splx(s2);
205 npcb_free(npcb, NPCB_REMOVE);
206 error = EIO;
207 break;
208 }
209 splx(s2);
210
211 soisconnected(so);
212
213 break;
214
215 case PRU_DISCONNECT: /* disconnect from peer */
216
217 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
218 printf("natm: disconnected check\n");
219 error = EIO;
220 break;
221 }
222 ifp = npcb->npcb_ifp;
223
224 /*
225 * disable rx
226 */
227
228 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
229 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
230 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
231 api.rxhand = npcb;
232 s2 = splnet();
233 if (ifp->if_ioctl != NULL)
234 ifp->if_ioctl(ifp, SIOCATMDIS, &api);
235 splx(s);
236
237 npcb_free(npcb, NPCB_REMOVE);
238 soisdisconnected(so);
239
240 break;
241
242 case PRU_SHUTDOWN: /* won't send any more data */
243 socantsendmore(so);
244 break;
245
246 case PRU_SEND: /* send this data */
247 if (control && control->m_len) {
248 m_freem(control);
249 m_freem(m);
250 error = EINVAL;
251 break;
252 }
253
254 /*
255 * send the data. we must put an atm_pseudohdr on first
256 */
257
258 M_PREPEND(m, sizeof(*aph), M_WAITOK);
259 if (m == NULL) {
260 error = ENOBUFS;
261 break;
262 }
263 aph = mtod(m, struct atm_pseudohdr *);
264 ATM_PH_VPI(aph) = npcb->npcb_vpi;
265 ATM_PH_SETVCI(aph, npcb->npcb_vci);
266 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
267
268 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
269
270 break;
271
272 case PRU_SENSE: /* return status into m */
273 /* return zero? */
274 break;
275
276 case PRU_PEERADDR: /* fetch peer's address */
277 snatm = mtod(nam, struct sockaddr_natm *);
278 bzero(snatm, sizeof(*snatm));
279 nam->m_len = snatm->snatm_len = sizeof(*snatm);
280 snatm->snatm_family = AF_NATM;
281 #if defined(__NetBSD__) || defined(__OpenBSD__)
282 bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
283 #elif defined(__FreeBSD__)
284 snprintf(snatm->snatm_if, sizeof(snatm->snatm_if), "%s%d",
285 npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit);
286 #endif
287 snatm->snatm_vci = npcb->npcb_vci;
288 snatm->snatm_vpi = npcb->npcb_vpi;
289 break;
290
291 case PRU_CONTROL: /* control operations on protocol */
292 /*
293 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
294 * SIOCXRAWATM and pass it to the driver.
295 */
296 if ((u_long)m == SIOCRAWATM) {
297 if (npcb->npcb_ifp == NULL) {
298 error = ENOTCONN;
299 break;
300 }
301 ario.npcb = npcb;
302 ario.rawvalue = *((int *)nam);
303 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM, &ario);
304 if (!error) {
305 if (ario.rawvalue)
306 npcb->npcb_flags |= NPCB_RAW;
307 else
308 npcb->npcb_flags &= ~(NPCB_RAW);
309 }
310
311 break;
312 }
313
314 error = EOPNOTSUPP;
315 break;
316
317 case PRU_BIND: /* bind socket to address */
318 case PRU_LISTEN: /* listen for connection */
319 case PRU_ACCEPT: /* accept connection from peer */
320 case PRU_CONNECT2: /* connect two sockets */
321 case PRU_ABORT: /* abort (fast DISCONNECT, DETATCH) */
322 /* (only happens if LISTEN socket) */
323 case PRU_RCVD: /* have taken data; more room now */
324 case PRU_FASTTIMO: /* 200ms timeout */
325 case PRU_SLOWTIMO: /* 500ms timeout */
326 case PRU_RCVOOB: /* retrieve out of band data */
327 case PRU_SENDOOB: /* send out of band data */
328 case PRU_PROTORCV: /* receive from below */
329 case PRU_PROTOSEND: /* send to below */
330 case PRU_SOCKADDR: /* fetch socket's address */
331 #ifdef DIAGNOSTIC
332 printf("natm: PRU #%d unsupported\n", req);
333 #endif
334 error = EOPNOTSUPP;
335 break;
336
337 default: panic("natm usrreq");
338 }
339
340 done:
341 splx(s);
342 return(error);
343 }
344
345 /*
346 * natmintr: splsoftnet interrupt
347 *
348 * note: we expect a socket pointer in rcvif rather than an interface
349 * pointer. we can get the interface pointer from the so's PCB if
350 * we really need it.
351 */
352
353 void
354 natmintr()
355
356 {
357 int s;
358 struct mbuf *m;
359 struct socket *so;
360 struct natmpcb *npcb;
361
362 mutex_enter(softnet_lock);
363 next:
364 s = splnet();
365 IF_DEQUEUE(&natmintrq, m);
366 splx(s);
367 if (m == NULL) {
368 mutex_exit(softnet_lock);
369 return;
370 }
371
372 #ifdef DIAGNOSTIC
373 if ((m->m_flags & M_PKTHDR) == 0)
374 panic("natmintr no HDR");
375 #endif
376
377 npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
378 so = npcb->npcb_socket;
379
380 s = splnet(); /* could have atm devs @ different levels */
381 npcb->npcb_inq--;
382 splx(s);
383
384 if (npcb->npcb_flags & NPCB_DRAIN) {
385 m_freem(m);
386 if (npcb->npcb_inq == 0)
387 FREE(npcb, M_PCB); /* done! */
388 goto next;
389 }
390
391 if (npcb->npcb_flags & NPCB_FREE) {
392 m_freem(m); /* drop */
393 goto next;
394 }
395
396 #ifdef NEED_TO_RESTORE_IFP
397 m->m_pkthdr.rcvif = npcb->npcb_ifp;
398 #else
399 #ifdef DIAGNOSTIC
400 m->m_pkthdr.rcvif = NULL; /* null it out to be safe */
401 #endif
402 #endif
403
404 if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
405 ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
406 #ifdef NATM_STAT
407 natm_sookcnt++;
408 natm_sookbytes += m->m_pkthdr.len;
409 #endif
410 sbappendrecord(&so->so_rcv, m);
411 sorwakeup(so);
412 } else {
413 #ifdef NATM_STAT
414 natm_sodropcnt++;
415 natm_sodropbytes += m->m_pkthdr.len;
416 #endif
417 m_freem(m);
418 }
419
420 goto next;
421 }
422
423 #if defined(__FreeBSD__)
424 NETISR_SET(NETISR_NATM, natmintr);
425 #endif
426
427
428 #ifdef notyet
429 /*
430 * natm0_sysctl: not used, but here in case we want to add something
431 * later...
432 */
433
434 int natm0_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
435
436 int *name;
437 u_int namelen;
438 void *oldp;
439 size_t *oldlenp;
440 void *newp;
441 size_t newlen;
442
443 {
444 /* All sysctl names at this level are terminal. */
445 if (namelen != 1)
446 return (ENOTDIR);
447 return (ENOPROTOOPT);
448 }
449
450 /*
451 * natm5_sysctl: not used, but here in case we want to add something
452 * later...
453 */
454
455 int natm5_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
456
457 int *name;
458 u_int namelen;
459 void *oldp;
460 size_t *oldlenp;
461 void *newp;
462 size_t newlen;
463
464 {
465 /* All sysctl names at this level are terminal. */
466 if (namelen != 1)
467 return (ENOTDIR);
468 return (ENOPROTOOPT);
469 }
470 #endif
Cache object: 9264c5db90450dbe774112991c6f1f83
|