📄 common.c
字号:
case ATM_GETNAMES: if (get_user(buf, &((struct atm_iobuf *) arg)->buffer)) { ret_val = -EFAULT; goto done; } if (get_user(len, &((struct atm_iobuf *) arg)->length)) { ret_val = -EFAULT; goto done; } size = 0; for (dev = atm_devs; dev; dev = dev->next) size += sizeof(int); if (size > len) { ret_val = -E2BIG; goto done; } tmp_buf = kmalloc(size,GFP_KERNEL); if (!tmp_buf) { ret_val = -ENOMEM; goto done; } for (dev = atm_devs; dev; dev = dev->next) *tmp_buf++ = dev->number; if (copy_to_user(buf,(char *) tmp_buf-size,size)) { ret_val = -EFAULT; goto done; } ret_val = put_user(size, &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0; goto done; case SIOCGSTAMP: /* borrowed from IP */ if (!vcc->timestamp.tv_sec) { ret_val = -ENOENT; goto done; } vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000; vcc->timestamp.tv_usec %= 1000000; ret_val = copy_to_user((void *) arg,&vcc->timestamp, sizeof(struct timeval)) ? -EFAULT : 0; goto done; case ATM_SETSC: printk(KERN_WARNING "ATM_SETSC is obsolete\n"); ret_val = 0; goto done; case ATMSIGD_CTRL: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } /* * The user/kernel protocol for exchanging signalling * info uses kernel pointers as opaque references, * so the holder of the file descriptor can scribble * on the kernel... so we should make sure that we * have the same privledges that /proc/kcore needs */ if (!capable(CAP_SYS_RAWIO)) { ret_val = -EPERM; goto done; } error = sigd_attach(vcc); if (!error) sock->state = SS_CONNECTED; ret_val = error; goto done;#ifdef CONFIG_ATM_CLIP case SIOCMKCLIP: if (!capable(CAP_NET_ADMIN)) ret_val = -EPERM; else ret_val = clip_create(arg); goto done; case ATMARPD_CTRL: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } error = atm_init_atmarp(vcc); if (!error) sock->state = SS_CONNECTED; ret_val = error; goto done; case ATMARP_MKIP: if (!capable(CAP_NET_ADMIN)) ret_val = -EPERM; else ret_val = clip_mkip(vcc,arg); goto done; case ATMARP_SETENTRY: if (!capable(CAP_NET_ADMIN)) ret_val = -EPERM; else ret_val = clip_setentry(vcc,arg); goto done; case ATMARP_ENCAP: if (!capable(CAP_NET_ADMIN)) ret_val = -EPERM; else ret_val = clip_encap(vcc,arg); goto done;#endif#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) case ATMLEC_CTRL: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } if (atm_lane_ops.lecd_attach == NULL) atm_lane_init(); if (atm_lane_ops.lecd_attach == NULL) { /* try again */ ret_val = -ENOSYS; goto done; } error = atm_lane_ops.lecd_attach(vcc, (int)arg); if (error >= 0) sock->state = SS_CONNECTED; ret_val = error; goto done; case ATMLEC_MCAST: if (!capable(CAP_NET_ADMIN)) ret_val = -EPERM; else ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg); goto done; case ATMLEC_DATA: if (!capable(CAP_NET_ADMIN)) ret_val = -EPERM; else ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg); goto done;#endif#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) case ATMMPC_CTRL: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } if (atm_mpoa_ops.mpoad_attach == NULL) atm_mpoa_init(); if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */ ret_val = -ENOSYS; goto done; } error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg); if (error >= 0) sock->state = SS_CONNECTED; ret_val = error; goto done; case ATMMPC_DATA: if (!capable(CAP_NET_ADMIN)) ret_val = -EPERM; else ret_val = atm_mpoa_ops.vcc_attach(vcc, arg); goto done;#endif#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) case SIOCSIFATMTCP: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } if (!atm_tcp_ops.attach) { ret_val = -ENOPKG; goto done; } fops_get (&atm_tcp_ops); error = atm_tcp_ops.attach(vcc,(int) arg); if (error >= 0) sock->state = SS_CONNECTED; else fops_put (&atm_tcp_ops); ret_val = error; goto done; case ATMTCP_CREATE: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } if (!atm_tcp_ops.create_persistent) { ret_val = -ENOPKG; goto done; } error = atm_tcp_ops.create_persistent((int) arg); if (error < 0) fops_put (&atm_tcp_ops); ret_val = error; goto done; case ATMTCP_REMOVE: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } if (!atm_tcp_ops.remove_persistent) { ret_val = -ENOPKG; goto done; } error = atm_tcp_ops.remove_persistent((int) arg); fops_put (&atm_tcp_ops); ret_val = error; goto done;#endif default: break; } if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) { ret_val = -EFAULT; goto done; } if (get_user(len,&((struct atmif_sioc *) arg)->length)) { ret_val = -EFAULT; goto done; } if (get_user(number,&((struct atmif_sioc *) arg)->number)) { ret_val = -EFAULT; goto done; } if (!(dev = atm_find_dev(number))) { ret_val = -ENODEV; goto done; } size = 0; switch (cmd) { case ATM_GETTYPE: size = strlen(dev->type)+1; if (copy_to_user(buf,dev->type,size)) { ret_val = -EFAULT; goto done; } break; case ATM_GETESI: size = ESI_LEN; if (copy_to_user(buf,dev->esi,size)) { ret_val = -EFAULT; goto done; } break; case ATM_SETESI: { int i; for (i = 0; i < ESI_LEN; i++) if (dev->esi[i]) { ret_val = -EEXIST; goto done; } } /* fall through */ case ATM_SETESIF: { unsigned char esi[ESI_LEN]; if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } if (copy_from_user(esi,buf,ESI_LEN)) { ret_val = -EFAULT; goto done; } memcpy(dev->esi,esi,ESI_LEN); ret_val = ESI_LEN; goto done; } case ATM_GETSTATZ: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } /* fall through */ case ATM_GETSTAT: size = sizeof(struct atm_dev_stats); error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ); if (error) { ret_val = error; goto done; } break; case ATM_GETCIRANGE: size = sizeof(struct atm_cirange); if (copy_to_user(buf,&dev->ci_range,size)) { ret_val = -EFAULT; goto done; } break; case ATM_GETLINKRATE: size = sizeof(int); if (copy_to_user(buf,&dev->link_rate,size)) { ret_val = -EFAULT; goto done; } break; case ATM_RSTADDR: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } reset_addr(dev); break; case ATM_ADDADDR: case ATM_DELADDR: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } { struct sockaddr_atmsvc addr; if (copy_from_user(&addr,buf,sizeof(addr))) { ret_val = -EFAULT; goto done; } if (cmd == ATM_ADDADDR) ret_val = add_addr(dev,&addr); else ret_val = del_addr(dev,&addr); goto done; } case ATM_GETADDR: size = get_addr(dev,buf,len); if (size < 0) ret_val = size; else /* may return 0, but later on size == 0 means "don't write the length" */ ret_val = put_user(size, &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0; goto done; case ATM_SETLOOP: if (__ATM_LM_XTRMT((int) (long) buf) && __ATM_LM_XTLOC((int) (long) buf) > __ATM_LM_XTRMT((int) (long) buf)) { ret_val = -EINVAL; goto done; } /* fall through */ case ATM_SETCIRANGE: case SONET_GETSTATZ: case SONET_SETDIAG: case SONET_CLRDIAG: case SONET_SETFRAMING: if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; goto done; } /* fall through */ default: if (!dev->ops->ioctl) { ret_val = -EINVAL; goto done; } size = dev->ops->ioctl(dev,cmd,buf); if (size < 0) { ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size); goto done; } } if (size) ret_val = put_user(size,&((struct atmif_sioc *) arg)->length) ? -EFAULT : 0; done: spin_unlock (&atm_dev_lock); return ret_val;}static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos){ int error; /* * Don't let the QoS change the already connected AAL type nor the * traffic class. */ if (qos->aal != vcc->qos.aal || qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class || qos->txtp.traffic_class != vcc->qos.txtp.traffic_class) return -EINVAL; error = adjust_tp(&qos->txtp,qos->aal); if (!error) error = adjust_tp(&qos->rxtp,qos->aal); if (error) return error; if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP; if (vcc->family == AF_ATMPVC) return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET); return svc_change_qos(vcc,qos);}static int check_tp(struct atm_trafprm *tp){ /* @@@ Should be merged with adjust_tp */ if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS) return 0; if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr && !tp->max_pcr) return -EINVAL; if (tp->min_pcr == ATM_MAX_PCR) return -EINVAL; if (tp->min_pcr && tp->max_pcr && tp->max_pcr != ATM_MAX_PCR && tp->min_pcr > tp->max_pcr) return -EINVAL; /* * We allow pcr to be outside [min_pcr,max_pcr], because later * adjustment may still push it in the valid range. */ return 0;}static int check_qos(struct atm_qos *qos){ int error; if (!qos->txtp.traffic_class && !qos->rxtp.traffic_class) return -EINVAL; if (qos->txtp.traffic_class != qos->rxtp.traffic_class && qos->txtp.traffic_class && qos->rxtp.traffic_class && qos->txtp.traffic_class != ATM_ANYCLASS && qos->rxtp.traffic_class != ATM_ANYCLASS) return -EINVAL; error = check_tp(&qos->txtp); if (error) return error; return check_tp(&qos->rxtp);}static int atm_do_setsockopt(struct socket *sock,int level,int optname, void *optval,int optlen){ struct atm_vcc *vcc; unsigned long value; int error; vcc = ATM_SD(sock); switch (optname) { case SO_ATMQOS: { struct atm_qos qos; if (copy_from_user(&qos,optval,sizeof(qos))) return -EFAULT; error = check_qos(&qos); if (error) return error; if (sock->state == SS_CONNECTED) return atm_change_qos(vcc,&qos); if (sock->state != SS_UNCONNECTED) return -EBADFD; vcc->qos = qos; set_bit(ATM_VF_HASQOS,&vcc->flags); return 0; } case SO_SETCLP: if (get_user(value,(unsigned long *) optval)) return -EFAULT; if (value) vcc->atm_options |= ATM_ATMOPT_CLP; else vcc->atm_options &= ~ATM_ATMOPT_CLP; return 0; default: if (level == SOL_SOCKET) return -EINVAL; break; } if (!vcc->dev || !vcc->dev->ops->setsockopt) return -EINVAL; return vcc->dev->ops->setsockopt(vcc,level,optname,optval,optlen);}static int atm_do_getsockopt(struct socket *sock,int level,int optname, void *optval,int optlen){ struct atm_vcc *vcc; vcc = ATM_SD(sock); switch (optname) { case SO_ATMQOS: if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EINVAL; return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ? -EFAULT : 0; case SO_SETCLP: return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 : 0,(unsigned long *) optval) ? -EFAULT : 0; case SO_ATMPVC: { struct sockaddr_atmpvc pvc; if (!vcc->dev || !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN; pvc.sap_family = AF_ATMPVC; pvc.sap_addr.itf = vcc->dev->number; pvc.sap_addr.vpi = vcc->vpi; pvc.sap_addr.vci = vcc->vci; return copy_to_user(optval,&pvc,sizeof(pvc)) ? -EFAULT : 0; } default: if (level == SOL_SOCKET) return -EINVAL; break; } if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL; return vcc->dev->ops->getsockopt(vcc,level,optname,optval,optlen);}int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, int optlen){ if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname)) return -EINVAL; return atm_do_setsockopt(sock,level,optname,optval,optlen);}int atm_getsockopt(struct socket *sock,int level,int optname, char *optval,int *optlen){ int len; if (get_user(len,optlen)) return -EFAULT; if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname)) return -EINVAL; return atm_do_getsockopt(sock,level,optname,optval,len);}/* * lane_mpoa_init.c: A couple of helper functions * to make modular LANE and MPOA client easier to implement *//* * This is how it goes: * * if xxxx is not compiled as module, call atm_xxxx_init_ops() * from here * else call atm_mpoa_init_ops() from init_module() within * the kernel when xxxx module is loaded * * In either case function pointers in struct atm_xxxx_ops * are initialized to their correct values. Either they * point to functions in the module or in the kernel */ extern struct atm_mpoa_ops atm_mpoa_ops; /* in common.c */extern struct atm_lane_ops atm_lane_ops; /* in common.c */#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)void atm_mpoa_init(void){#ifndef CONFIG_ATM_MPOA_MODULE /* not module */ atm_mpoa_init_ops(&atm_mpoa_ops);#else request_module("mpoa");#endif return;}#endif#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, unsigned char *addr) = NULL;void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) = NULL;#if defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE)EXPORT_SYMBOL(br_fdb_get_hook);EXPORT_SYMBOL(br_fdb_put_hook);#endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */void atm_lane_init(void){#ifndef CONFIG_ATM_LANE_MODULE /* not module */ atm_lane_init_ops(&atm_lane_ops);#else request_module("lec");#endif return;} #endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -