FreeBSD/Linux Kernel Cross Reference
sys/netnatm/natm.c
1 /* $NetBSD: natm.c,v 1.12.24.1 2008/02/22 22:00:00 bouyer 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.12.24.1 2008/02/22 22:00:00 bouyer 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 = (caddr_t) (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(so);
141
142 break;
143
144 case PRU_CONNECT: /* establish connection to peer */
145
146 /*
147 * validate nam and npcb
148 */
149
150 if (nam->m_len != sizeof(*snatm)) {
151 error = EINVAL;
152 break;
153 }
154 snatm = mtod(nam, struct sockaddr_natm *);
155 if (snatm->snatm_len != sizeof(*snatm) ||
156 (npcb->npcb_flags & NPCB_FREE) == 0) {
157 error = EINVAL;
158 break;
159 }
160 if (snatm->snatm_family != AF_NATM) {
161 error = EAFNOSUPPORT;
162 break;
163 }
164
165 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
166 since ifunit() uses strcmp */
167
168 /*
169 * convert interface string to ifp, validate.
170 */
171
172 ifp = ifunit(snatm->snatm_if);
173 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
174 error = ENXIO;
175 break;
176 }
177 if (ifp->if_output != atm_output) {
178 error = EAFNOSUPPORT;
179 break;
180 }
181
182
183 /*
184 * register us with the NATM PCB layer
185 */
186
187 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
188 error = EADDRINUSE;
189 break;
190 }
191
192 /*
193 * enable rx
194 */
195
196 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
197 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
198 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
199 api.rxhand = npcb;
200 s2 = splnet();
201 if (ifp->if_ioctl == NULL ||
202 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
203 splx(s2);
204 npcb_free(npcb, NPCB_REMOVE);
205 error = EIO;
206 break;
207 }
208 splx(s2);
209
210 soisconnected(so);
211
212 break;
213
214 case PRU_DISCONNECT: /* disconnect from peer */
215
216 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
217 printf("natm: disconnected check\n");
218 error = EIO;
219 break;
220 }
221 ifp = npcb->npcb_ifp;
222
223 /*
224 * disable rx
225 */
226
227 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
228 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
229 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
230 api.rxhand = npcb;
231 s2 = splnet();
232 if (ifp->if_ioctl != NULL)
233 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
234 splx(s);
235
236 npcb_free(npcb, NPCB_REMOVE);
237 soisdisconnected(so);
238
239 break;
240
241 case PRU_SHUTDOWN: /* won't send any more data */
242 socantsendmore(so);
243 break;
244
245 case PRU_SEND: /* send this data */
246 if (control && control->m_len) {
247 m_freem(control);
248 m_freem(m);
249 error = EINVAL;
250 break;
251 }
252
253 /*
254 * send the data. we must put an atm_pseudohdr on first
255 */
256
257 M_PREPEND(m, sizeof(*aph), M_WAITOK);
258 if (m == NULL) {
259 error = ENOBUFS;
260 break;
261 }
262 aph = mtod(m, struct atm_pseudohdr *);
263 ATM_PH_VPI(aph) = npcb->npcb_vpi;
264 ATM_PH_SETVCI(aph, npcb->npcb_vci);
265 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
266
267 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
268
269 break;
270
271 case PRU_SENSE: /* return status into m */
272 /* return zero? */
273 break;
274
275 case PRU_PEERADDR: /* fetch peer's address */
276 snatm = mtod(nam, struct sockaddr_natm *);
277 bzero(snatm, sizeof(*snatm));
278 nam->m_len = snatm->snatm_len = sizeof(*snatm);
279 snatm->snatm_family = AF_NATM;
280 #if defined(__NetBSD__) || defined(__OpenBSD__)
281 bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
282 #elif defined(__FreeBSD__)
283 snprintf(snatm->snatm_if, sizeof(snatm->snatm_if), "%s%d",
284 npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit);
285 #endif
286 snatm->snatm_vci = npcb->npcb_vci;
287 snatm->snatm_vpi = npcb->npcb_vpi;
288 break;
289
290 case PRU_CONTROL: /* control operations on protocol */
291 /*
292 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
293 * SIOCXRAWATM and pass it to the driver.
294 */
295 if ((u_long)m == SIOCRAWATM) {
296 if (npcb->npcb_ifp == NULL) {
297 error = ENOTCONN;
298 break;
299 }
300 ario.npcb = npcb;
301 ario.rawvalue = *((int *)nam);
302 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp,
303 SIOCXRAWATM, (caddr_t) &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 next:
363 s = splnet();
364 IF_DEQUEUE(&natmintrq, m);
365 splx(s);
366 if (m == NULL)
367 return;
368
369 #ifdef DIAGNOSTIC
370 if ((m->m_flags & M_PKTHDR) == 0)
371 panic("natmintr no HDR");
372 #endif
373
374 npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
375 so = npcb->npcb_socket;
376
377 s = splnet(); /* could have atm devs @ different levels */
378 npcb->npcb_inq--;
379 splx(s);
380
381 if (npcb->npcb_flags & NPCB_DRAIN) {
382 m_freem(m);
383 if (npcb->npcb_inq == 0)
384 FREE(npcb, M_PCB); /* done! */
385 goto next;
386 }
387
388 if (npcb->npcb_flags & NPCB_FREE) {
389 m_freem(m); /* drop */
390 goto next;
391 }
392
393 #ifdef NEED_TO_RESTORE_IFP
394 m->m_pkthdr.rcvif = npcb->npcb_ifp;
395 #else
396 #ifdef DIAGNOSTIC
397 m->m_pkthdr.rcvif = NULL; /* null it out to be safe */
398 #endif
399 #endif
400
401 if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
402 ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
403 #ifdef NATM_STAT
404 natm_sookcnt++;
405 natm_sookbytes += m->m_pkthdr.len;
406 #endif
407 sbappendrecord(&so->so_rcv, m);
408 sorwakeup(so);
409 } else {
410 #ifdef NATM_STAT
411 natm_sodropcnt++;
412 natm_sodropbytes += m->m_pkthdr.len;
413 #endif
414 m_freem(m);
415 }
416
417 goto next;
418 }
419
420 #if defined(__FreeBSD__)
421 NETISR_SET(NETISR_NATM, natmintr);
422 #endif
423
424
425 #ifdef notyet
426 /*
427 * natm0_sysctl: not used, but here in case we want to add something
428 * later...
429 */
430
431 int natm0_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
432
433 int *name;
434 u_int namelen;
435 void *oldp;
436 size_t *oldlenp;
437 void *newp;
438 size_t newlen;
439
440 {
441 /* All sysctl names at this level are terminal. */
442 if (namelen != 1)
443 return (ENOTDIR);
444 return (ENOPROTOOPT);
445 }
446
447 /*
448 * natm5_sysctl: not used, but here in case we want to add something
449 * later...
450 */
451
452 int natm5_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
453
454 int *name;
455 u_int namelen;
456 void *oldp;
457 size_t *oldlenp;
458 void *newp;
459 size_t newlen;
460
461 {
462 /* All sysctl names at this level are terminal. */
463 if (namelen != 1)
464 return (ENOTDIR);
465 return (ENOPROTOOPT);
466 }
467 #endif
Cache object: 1ed8b0d3b5a34903f32aed181aee36ff
|