📄 af_rose.c
字号:
len = min(len, sizeof(int)); if (put_user(len, optlen)) return -EFAULT; return copy_to_user(optval, &val, len) ? -EFAULT : 0;}static int rose_listen(struct socket *sock, int backlog){ struct sock *sk = sock->sk; if (sk->state != TCP_LISTEN) { sk->protinfo.rose->dest_ndigis = 0; memset(&sk->protinfo.rose->dest_addr, '\0', ROSE_ADDR_LEN); memset(&sk->protinfo.rose->dest_call, '\0', AX25_ADDR_LEN); memset(sk->protinfo.rose->dest_digis, '\0', AX25_ADDR_LEN*ROSE_MAX_DIGIS); sk->max_ack_backlog = backlog; sk->state = TCP_LISTEN; return 0; } return -EOPNOTSUPP;}static int rose_create(struct socket *sock, int protocol){ struct sock *sk; rose_cb *rose; if (sock->type != SOCK_SEQPACKET || protocol != 0) return -ESOCKTNOSUPPORT; if ((sk = rose_alloc_sock()) == NULL) return -ENOMEM; rose = sk->protinfo.rose; sock_init_data(sock, sk); skb_queue_head_init(&rose->ack_queue);#ifdef M_BIT skb_queue_head_init(&rose->frag_queue); rose->fraglen = 0;#endif sock->ops = &rose_proto_ops; sk->protocol = protocol; init_timer(&rose->timer); init_timer(&rose->idletimer); rose->t1 = sysctl_rose_call_request_timeout; rose->t2 = sysctl_rose_reset_request_timeout; rose->t3 = sysctl_rose_clear_request_timeout; rose->hb = sysctl_rose_ack_hold_back_timeout; rose->idle = sysctl_rose_no_activity_timeout; rose->state = ROSE_STATE_0; return 0;}static struct sock *rose_make_new(struct sock *osk){ struct sock *sk; rose_cb *rose; if (osk->type != SOCK_SEQPACKET) return NULL; if ((sk = rose_alloc_sock()) == NULL) return NULL; rose = sk->protinfo.rose; sock_init_data(NULL, sk); skb_queue_head_init(&rose->ack_queue);#ifdef M_BIT skb_queue_head_init(&rose->frag_queue); rose->fraglen = 0;#endif sk->type = osk->type; sk->socket = osk->socket; sk->priority = osk->priority; sk->protocol = osk->protocol; sk->rcvbuf = osk->rcvbuf; sk->sndbuf = osk->sndbuf; sk->debug = osk->debug; sk->state = TCP_ESTABLISHED; sk->sleep = osk->sleep; sk->zapped = osk->zapped; init_timer(&rose->timer); init_timer(&rose->idletimer); rose->t1 = osk->protinfo.rose->t1; rose->t2 = osk->protinfo.rose->t2; rose->t3 = osk->protinfo.rose->t3; rose->hb = osk->protinfo.rose->hb; rose->idle = osk->protinfo.rose->idle; rose->defer = osk->protinfo.rose->defer; rose->device = osk->protinfo.rose->device; rose->qbitincl = osk->protinfo.rose->qbitincl; return sk;}static int rose_release(struct socket *sock){ struct sock *sk = sock->sk; if (sk == NULL) return 0; switch (sk->protinfo.rose->state) { case ROSE_STATE_0: rose_disconnect(sk, 0, -1, -1); rose_destroy_socket(sk); break; case ROSE_STATE_2: sk->protinfo.rose->neighbour->use--; rose_disconnect(sk, 0, -1, -1); rose_destroy_socket(sk); break; case ROSE_STATE_1: case ROSE_STATE_3: case ROSE_STATE_4: case ROSE_STATE_5: rose_clear_queues(sk); rose_stop_idletimer(sk); rose_write_internal(sk, ROSE_CLEAR_REQUEST); rose_start_t3timer(sk); sk->protinfo.rose->state = ROSE_STATE_2; sk->state = TCP_CLOSE; sk->shutdown |= SEND_SHUTDOWN; sk->state_change(sk); sk->dead = 1; sk->destroy = 1; break; default: break; } sock->sk = NULL; sk->socket = NULL; /* Not used, but we should do this. **/ return 0;}static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){ struct sock *sk = sock->sk; struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; struct net_device *dev; ax25_address *user, *source; int n; if (sk->zapped == 0) return -EINVAL; if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose)) return -EINVAL; if (addr->srose_family != AF_ROSE) return -EINVAL; if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1) return -EINVAL; if (addr->srose_ndigis > ROSE_MAX_DIGIS) return -EINVAL; if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) { SOCK_DEBUG(sk, "ROSE: bind failed: invalid address\n"); return -EADDRNOTAVAIL; } source = &addr->srose_call; if ((user = ax25_findbyuid(current->euid)) == NULL) { if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) return -EACCES; user = source; } sk->protinfo.rose->source_addr = addr->srose_addr; sk->protinfo.rose->source_call = *user; sk->protinfo.rose->device = dev; sk->protinfo.rose->source_ndigis = addr->srose_ndigis; if (addr_len == sizeof(struct full_sockaddr_rose)) { struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr; for (n = 0 ; n < addr->srose_ndigis ; n++) sk->protinfo.rose->source_digis[n] = full_addr->srose_digis[n]; } else { if (sk->protinfo.rose->source_ndigis == 1) { sk->protinfo.rose->source_digis[0] = addr->srose_digi; } } rose_insert_socket(sk); sk->zapped = 0; SOCK_DEBUG(sk, "ROSE: socket is bound\n"); return 0;}static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags){ struct sock *sk = sock->sk; struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; unsigned char cause, diagnostic; ax25_address *user; struct net_device *dev; int n; if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; return 0; /* Connect completed during a ERESTARTSYS event */ } if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) { sock->state = SS_UNCONNECTED; return -ECONNREFUSED; } if (sk->state == TCP_ESTABLISHED) return -EISCONN; /* No reconnect on a seqpacket socket */ sk->state = TCP_CLOSE; sock->state = SS_UNCONNECTED; if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose)) return -EINVAL; if (addr->srose_family != AF_ROSE) return -EINVAL; if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1) return -EINVAL; if (addr->srose_ndigis > ROSE_MAX_DIGIS) return -EINVAL; /* Source + Destination digis should not exceed ROSE_MAX_DIGIS */ if ((sk->protinfo.rose->source_ndigis + addr->srose_ndigis) > ROSE_MAX_DIGIS) return -EINVAL; if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic)) == NULL) return -ENETUNREACH; if ((sk->protinfo.rose->lci = rose_new_lci(sk->protinfo.rose->neighbour)) == 0) return -ENETUNREACH; if (sk->zapped) { /* Must bind first - autobinding in this may or may not work */ sk->zapped = 0; if ((dev = rose_dev_first()) == NULL) return -ENETUNREACH; if ((user = ax25_findbyuid(current->euid)) == NULL) return -EINVAL; memcpy(&sk->protinfo.rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN); sk->protinfo.rose->source_call = *user; sk->protinfo.rose->device = dev; rose_insert_socket(sk); /* Finish the bind */ } sk->protinfo.rose->dest_addr = addr->srose_addr; sk->protinfo.rose->dest_call = addr->srose_call; sk->protinfo.rose->rand = ((int)sk->protinfo.rose & 0xFFFF) + sk->protinfo.rose->lci; sk->protinfo.rose->dest_ndigis = addr->srose_ndigis; if (addr_len == sizeof(struct full_sockaddr_rose)) { struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr; for (n = 0 ; n < addr->srose_ndigis ; n++) sk->protinfo.rose->dest_digis[n] = full_addr->srose_digis[n]; } else { if (sk->protinfo.rose->dest_ndigis == 1) { sk->protinfo.rose->dest_digis[0] = addr->srose_digi; } } /* Move to connecting socket, start sending Connect Requests */ sock->state = SS_CONNECTING; sk->state = TCP_SYN_SENT; sk->protinfo.rose->state = ROSE_STATE_1; sk->protinfo.rose->neighbour->use++; rose_write_internal(sk, ROSE_CALL_REQUEST); rose_start_heartbeat(sk); rose_start_t1timer(sk); /* Now the loop */ if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return -EINPROGRESS; cli(); /* To avoid races on the sleep */ /* * A Connect Ack with Choke or timeout or failed routing will go to closed. */ while (sk->state == TCP_SYN_SENT) { interruptible_sleep_on(sk->sleep); if (signal_pending(current)) { sti(); return -ERESTARTSYS; } } if (sk->state != TCP_ESTABLISHED) { sti(); sock->state = SS_UNCONNECTED; return sock_error(sk); /* Always set at this point */ } sock->state = SS_CONNECTED; sti(); return 0;}static int rose_accept(struct socket *sock, struct socket *newsock, int flags){ struct sock *sk; struct sock *newsk; struct sk_buff *skb; if ((sk = sock->sk) == NULL) return -EINVAL; if (sk->type != SOCK_SEQPACKET) return -EOPNOTSUPP; if (sk->state != TCP_LISTEN) return -EINVAL; /* * The write queue this time is holding sockets ready to use * hooked into the SABM we saved */ do { cli(); if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { if (flags & O_NONBLOCK) { sti(); return -EWOULDBLOCK; } interruptible_sleep_on(sk->sleep); if (signal_pending(current)) { sti(); return -ERESTARTSYS; } } } while (skb == NULL); newsk = skb->sk; newsk->pair = NULL; newsk->socket = newsock; newsk->sleep = &newsock->wait; sti(); /* Now attach up the new socket */ skb->sk = NULL; kfree_skb(skb); sk->ack_backlog--; newsock->sk = newsk; return 0;}static int rose_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer){ struct full_sockaddr_rose *srose = (struct full_sockaddr_rose *)uaddr; struct sock *sk = sock->sk; int n; if (peer != 0) { if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; srose->srose_family = AF_ROSE; srose->srose_addr = sk->protinfo.rose->dest_addr; srose->srose_call = sk->protinfo.rose->dest_call; srose->srose_ndigis = sk->protinfo.rose->dest_ndigis; for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++) srose->srose_digis[n] = sk->protinfo.rose->dest_digis[n]; } else { srose->srose_family = AF_ROSE; srose->srose_addr = sk->protinfo.rose->source_addr; srose->srose_call = sk->protinfo.rose->source_call; srose->srose_ndigis = sk->protinfo.rose->source_ndigis; for (n = 0 ; n < sk->protinfo.rose->source_ndigis ; n++) srose->srose_digis[n] = sk->protinfo.rose->source_digis[n]; } *uaddr_len = sizeof(struct full_sockaddr_rose); return 0;}int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct rose_neigh *neigh, unsigned int lci){ struct sock *sk; struct sock *make; struct rose_facilities_struct facilities; int n, len; skb->sk = NULL; /* Initially we don't know who it's for */ /* * skb->data points to the rose frame start */ memset(&facilities, 0x00, sizeof(struct rose_facilities_struct)); len = (((skb->data[3] >> 4) & 0x0F) + 1) / 2; len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2; if (!rose_parse_facilities(skb->data + len + 4, &facilities)) { rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76); return 0; } sk = rose_find_listener(&facilities.source_addr, &facilities.source_call); /* * We can't accept the Call Request. */ if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = rose_make_new(sk)) == NULL) { rose_transmit_clear_request(neigh, lci, ROSE_NETWORK_CONGESTION, 120); return 0; } skb->sk = make; make->state = TCP_ESTABLISHED; make->protinfo.rose->lci = lci; make->protinfo.rose->dest_addr = facilities.dest_addr; make->protinfo.rose->dest_call = facilities.dest_call; make->protinfo.rose->dest_ndigis = facilities.dest_ndigis; for (n = 0 ; n < facilities.dest_ndigis ; n++) make->protinfo.rose->dest_digis[n] = facilities.dest_digis[n]; make->protinfo.rose->source_addr = facilities.source_addr; make->protinfo.rose->source_call = facilities.source_call; make->protinfo.rose->source_ndigis = facilities.source_ndigis; for (n = 0 ; n < facilities.source_ndigis ; n++) make->protinfo.rose->source_digis[n]= facilities.source_digis[n]; make->protinfo.rose->neighbour = neigh; make->protinfo.rose->device = dev; make->protinfo.rose->facilities = facilities; make->protinfo.rose->neighbour->use++; if (sk->protinfo.rose->defer) { make->protinfo.rose->state = ROSE_STATE_5; } else { rose_write_internal(make, ROSE_CALL_ACCEPTED); make->protinfo.rose->state = ROSE_STATE_3; rose_start_idletimer(make); } make->protinfo.rose->condition = 0x00; make->protinfo.rose->vs = 0; make->protinfo.rose->va = 0; make->protinfo.rose->vr = 0; make->protinfo.rose->vl = 0; sk->ack_backlog++; make->pair = sk; rose_insert_socket(make); skb_queue_head(&sk->receive_queue, skb); rose_start_heartbeat(make); if (!sk->dead) sk->data_ready(sk, skb->len); return 1;}static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct sockaddr_rose *usrose = (struct sockaddr_rose *)msg->msg_name; int err; struct full_sockaddr_rose srose; struct sk_buff *skb; unsigned char *asmptr; int n, size, qbit = 0; if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) return -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -